Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
April 2020
- 87 participants
- 854 discussions
[PATCH v2 2/3] windowscodecs: Fix IWICBitmapDecoder::CopyPalette for a not initialized case in the GIF decoder.
by Dmitry Timoshkov 27 Apr '20
by Dmitry Timoshkov 27 Apr '20
27 Apr '20
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/windowscodecs/gifformat.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c
index fc8f4b1c3e..5d5a3a07a2 100644
--- a/dlls/windowscodecs/gifformat.c
+++ b/dlls/windowscodecs/gifformat.c
@@ -1187,6 +1187,9 @@ static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalet
TRACE("(%p,%p)\n", iface, palette);
+ if (!This->gif)
+ return WINCODEC_ERR_WRONGSTATE;
+
cm = This->gif->SColorMap;
if (cm)
{
--
2.26.2
2
1
[PATCH v2 1/3] windowscodecs: Add initial implementation of the GIF encoder.
by Dmitry Timoshkov 27 Apr '20
by Dmitry Timoshkov 27 Apr '20
27 Apr '20
v2: Correcty indicate when write_source() should use an external palette.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/gdiplus/tests/image.c | 14 +-
dlls/windowscodecs/clsfactory.c | 1 +
dlls/windowscodecs/gifformat.c | 1012 ++++++++++++++++-
dlls/windowscodecs/regsvr.c | 10 +
dlls/windowscodecs/wincodecs_private.h | 1 +
dlls/windowscodecs/windowscodecs_wincodec.idl | 7 +
6 files changed, 1003 insertions(+), 42 deletions(-)
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index 145eadbfd3..956e55302a 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -5115,14 +5115,13 @@ static void test_supported_encoders(void)
{
LPCWSTR mime;
const GUID *format;
- BOOL todo;
} td[] =
{
- { bmp_mimetype, &ImageFormatBMP, FALSE },
- { jpeg_mimetype, &ImageFormatJPEG, FALSE },
- { gif_mimetype, &ImageFormatGIF, TRUE },
- { tiff_mimetype, &ImageFormatTIFF, FALSE },
- { png_mimetype, &ImageFormatPNG, FALSE }
+ { bmp_mimetype, &ImageFormatBMP },
+ { jpeg_mimetype, &ImageFormatJPEG },
+ { gif_mimetype, &ImageFormatGIF },
+ { tiff_mimetype, &ImageFormatTIFF },
+ { png_mimetype, &ImageFormatPNG }
};
GUID format, clsid;
BOOL ret;
@@ -5148,8 +5147,7 @@ static void test_supported_encoders(void)
ok(hr == S_OK, "CreateStreamOnHGlobal error %#x\n", hr);
status = GdipSaveImageToStream((GpImage *)bm, stream, &clsid, NULL);
- todo_wine_if (td[i].todo)
- ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
+ ok(status == Ok, "GdipSaveImageToStream error %d\n", status);
IStream_Release(stream);
}
diff --git a/dlls/windowscodecs/clsfactory.c b/dlls/windowscodecs/clsfactory.c
index d3cd9f34aa..21197993ca 100644
--- a/dlls/windowscodecs/clsfactory.c
+++ b/dlls/windowscodecs/clsfactory.c
@@ -52,6 +52,7 @@ static const classinfo wic_classes[] = {
{&CLSID_WICPngEncoder, PngEncoder_CreateInstance},
{&CLSID_WICBmpEncoder, BmpEncoder_CreateInstance},
{&CLSID_WICGifDecoder, GifDecoder_CreateInstance},
+ {&CLSID_WICGifEncoder, GifEncoder_CreateInstance},
{&CLSID_WICIcoDecoder, IcoDecoder_CreateInstance},
{&CLSID_WICJpegDecoder, JpegDecoder_CreateInstance},
{&CLSID_WICJpegEncoder, JpegEncoder_CreateInstance},
diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c
index df202ba45a..fc8f4b1c3e 100644
--- a/dlls/windowscodecs/gifformat.c
+++ b/dlls/windowscodecs/gifformat.c
@@ -1,6 +1,6 @@
/*
* Copyright 2009 Vincent Povirk for CodeWeavers
- * Copyright 2012 Dmitry Timoshkov
+ * Copyright 2012,2016 Dmitry Timoshkov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,6 +36,40 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+#include "pshpack1.h"
+
+struct logical_screen_descriptor
+{
+ char signature[6];
+ USHORT width;
+ USHORT height;
+ BYTE packed;
+ /* global_color_table_flag : 1;
+ * color_resolution : 3;
+ * sort_flag : 1;
+ * global_color_table_size : 3;
+ */
+ BYTE background_color_index;
+ BYTE pixel_aspect_ratio;
+};
+
+struct image_descriptor
+{
+ USHORT left;
+ USHORT top;
+ USHORT width;
+ USHORT height;
+ BYTE packed;
+ /* local_color_table_flag : 1;
+ * interlace_flag : 1;
+ * sort_flag : 1;
+ * reserved : 2;
+ * local_color_table_size : 3;
+ */
+};
+
+#include "poppack.h"
+
static LPWSTR strdupAtoW(const char *src)
{
int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
@@ -47,22 +81,7 @@ static LPWSTR strdupAtoW(const char *src)
static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
MetadataItem **items, DWORD *count)
{
-#include "pshpack1.h"
- struct logical_screen_descriptor
- {
- char signature[6];
- USHORT width;
- USHORT height;
- BYTE packed;
- /* global_color_table_flag : 1;
- * color_resolution : 3;
- * sort_flag : 1;
- * global_color_table_size : 3;
- */
- BYTE background_color_index;
- BYTE pixel_aspect_ratio;
- } lsd_data;
-#include "poppack.h"
+ struct logical_screen_descriptor lsd_data;
HRESULT hr;
ULONG bytesread, i;
MetadataItem *result;
@@ -147,23 +166,6 @@ HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
}
-#include "pshpack1.h"
-struct image_descriptor
-{
- USHORT left;
- USHORT top;
- USHORT width;
- USHORT height;
- BYTE packed;
- /* local_color_table_flag : 1;
- * interlace_flag : 1;
- * sort_flag : 1;
- * reserved : 2;
- * local_color_table_size : 3;
- */
-};
-#include "poppack.h"
-
static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
MetadataItem **items, DWORD *count)
{
@@ -1449,3 +1451,945 @@ HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
return ret;
}
+
+typedef struct GifEncoder
+{
+ IWICBitmapEncoder IWICBitmapEncoder_iface;
+ LONG ref;
+ IStream *stream;
+ CRITICAL_SECTION lock;
+ BOOL initialized, info_written, committed;
+ UINT n_frames;
+ WICColor palette[256];
+ UINT colors;
+} GifEncoder;
+
+static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
+{
+ return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
+}
+
+typedef struct GifFrameEncode
+{
+ IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
+ LONG ref;
+ GifEncoder *encoder;
+ BOOL initialized, interlace, committed;
+ UINT width, height, lines;
+ double xres, yres;
+ WICColor palette[256];
+ UINT colors;
+ BYTE *image_data;
+} GifFrameEncode;
+
+static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
+{
+ return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
+}
+
+static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
+{
+ TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
+
+ if (!ppv) return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, iid) ||
+ IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
+ {
+ IWICBitmapFrameEncode_AddRef(iface);
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+
+ if (!ref)
+ {
+ IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
+ HeapFree(GetProcessHeap(), 0, This->image_data);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, options);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (!This->initialized)
+ {
+ This->initialized = TRUE;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%u,%u\n", iface, width, height);
+
+ if (!width || !height) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ HeapFree(GetProcessHeap(), 0, This->image_data);
+
+ This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height);
+ if (This->image_data)
+ {
+ This->width = width;
+ This->height = height;
+ hr = S_OK;
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%f,%f\n", iface, xres, yres);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ This->xres = xres;
+ This->yres = yres;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%s\n", iface, debugstr_guid(format));
+
+ if (!format) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ *format = GUID_WICPixelFormat8bppIndexed;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
+{
+ FIXME("%p,%u,%p: stub\n", iface, count, context);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, palette);
+
+ if (!palette) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+ else
+ hr = WINCODEC_ERR_NOTINITIALIZED;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
+{
+ FIXME("%p,%p: stub\n", iface, thumbnail);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
+
+ if (!pixels) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized && This->image_data)
+ {
+ if (This->lines + lines <= This->height)
+ {
+ UINT i;
+ BYTE *src, *dst;
+
+ src = pixels;
+ dst = This->image_data + This->lines * This->width;
+
+ for (i = 0; i < lines; i++)
+ {
+ memcpy(dst, src, This->width);
+ src += stride;
+ dst += This->width;
+ }
+
+ This->lines += lines;
+ hr = S_OK;
+ }
+ else
+ hr = E_INVALIDARG;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%p\n", iface, source, rc);
+
+ if (!source) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->initialized)
+ {
+ const GUID *format = &GUID_WICPixelFormat8bppIndexed;
+
+ hr = configure_write_source(iface, source, rc, format,
+ This->width, This->height, This->xres, This->yres);
+ if (hr == S_OK)
+ hr = write_source(iface, source, rc, format, 8, !This->colors, This->width, This->height);
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+#define LZW_DICT_SIZE (1 << 12)
+
+struct lzw_dict
+{
+ short prefix[LZW_DICT_SIZE];
+ unsigned char suffix[LZW_DICT_SIZE];
+};
+
+struct lzw_state
+{
+ struct lzw_dict dict;
+ short init_code_bits, code_bits, next_code, clear_code, eof_code;
+ unsigned bits_buf;
+ int bits_count;
+ int (*user_write_data)(void *user_ptr, void *data, int length);
+ void *user_ptr;
+};
+
+struct input_stream
+{
+ unsigned len;
+ const BYTE *in;
+};
+
+struct output_stream
+{
+ struct
+ {
+ unsigned char len;
+ char data[255];
+ } gif_block;
+ IStream *out;
+};
+
+static int lzw_output_code(struct lzw_state *state, short code)
+{
+ state->bits_buf |= code << state->bits_count;
+ state->bits_count += state->code_bits;
+
+ while (state->bits_count >= 8)
+ {
+ unsigned char byte = (unsigned char)state->bits_buf;
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ state->bits_buf >>= 8;
+ state->bits_count -= 8;
+ }
+
+ return 1;
+}
+
+static inline int lzw_output_clear_code(struct lzw_state *state)
+{
+ return lzw_output_code(state, state->clear_code);
+}
+
+static inline int lzw_output_eof_code(struct lzw_state *state)
+{
+ return lzw_output_code(state, state->eof_code);
+}
+
+static int lzw_flush_bits(struct lzw_state *state)
+{
+ unsigned char byte;
+
+ while (state->bits_count >= 8)
+ {
+ byte = (unsigned char)state->bits_buf;
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ state->bits_buf >>= 8;
+ state->bits_count -= 8;
+ }
+
+ if (state->bits_count)
+ {
+ static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
+
+ byte = (unsigned char)state->bits_buf & mask[state->bits_count];
+ if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
+ return 0;
+ }
+
+ state->bits_buf = 0;
+ state->bits_count = 0;
+
+ return 1;
+}
+
+static void lzw_dict_reset(struct lzw_state *state)
+{
+ int i;
+
+ state->code_bits = state->init_code_bits + 1;
+ state->next_code = (1 << state->init_code_bits) + 2;
+
+ for(i = 0; i < LZW_DICT_SIZE; i++)
+ {
+ state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
+ state->dict.suffix[i] = 0;
+ }
+}
+
+static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
+{
+ state->init_code_bits = init_code_bits;
+ state->clear_code = 1 << init_code_bits;
+ state->eof_code = state->clear_code + 1;
+ state->bits_buf = 0;
+ state->bits_count = 0;
+ state->user_write_data = user_write_data;
+ state->user_ptr = user_ptr;
+
+ lzw_dict_reset(state);
+}
+
+static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
+{
+ if (state->next_code < LZW_DICT_SIZE)
+ {
+ state->dict.prefix[state->next_code] = prefix;
+ state->dict.suffix[state->next_code] = suffix;
+
+ if ((state->next_code & (state->next_code - 1)) == 0)
+ state->code_bits++;
+
+ state->next_code++;
+ return state->next_code;
+ }
+
+ return -1;
+}
+
+static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
+{
+ short i;
+
+ for (i = 0; i < state->next_code; i++)
+ {
+ if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
+ return i;
+ }
+
+ return -1;
+}
+
+static inline int write_byte(struct output_stream *out, char byte)
+{
+ if (out->gif_block.len == 255)
+ {
+ if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
+ return 0;
+
+ out->gif_block.len = 0;
+ }
+
+ out->gif_block.data[out->gif_block.len++] = byte;
+
+ return 1;
+}
+
+static int write_data(void *user_ptr, void *user_data, int length)
+{
+ unsigned char *data = user_data;
+ struct output_stream *out = user_ptr;
+ int len = length;
+
+ while (len-- > 0)
+ {
+ if (!write_byte(out, *data++)) return 0;
+ }
+
+ return length;
+}
+
+static int flush_output_data(void *user_ptr)
+{
+ struct output_stream *out = user_ptr;
+
+ if (out->gif_block.len)
+ {
+ if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
+ return 0;
+ }
+
+ /* write GIF block terminator */
+ out->gif_block.len = 0;
+ return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
+}
+
+static inline int read_byte(struct input_stream *in, unsigned char *byte)
+{
+ if (in->len)
+ {
+ in->len--;
+ *byte = *in->in++;
+ return 1;
+ }
+
+ return 0;
+}
+
+static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
+{
+ struct input_stream in;
+ struct output_stream out;
+ struct lzw_state state;
+ short init_code_bits, prefix, code;
+ unsigned char suffix;
+
+ in.in = in_data;
+ in.len = in_size;
+
+ out.gif_block.len = 0;
+ out.out = out_stream;
+
+ init_code_bits = suffix = 8;
+ if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
+ return E_FAIL;
+
+ lzw_state_init(&state, init_code_bits, write_data, &out);
+
+ if (!lzw_output_clear_code(&state))
+ return E_FAIL;
+
+ if (read_byte(&in, &suffix))
+ {
+ prefix = suffix;
+
+ while (read_byte(&in, &suffix))
+ {
+ code = lzw_dict_lookup(&state, prefix, suffix);
+ if (code == -1)
+ {
+ if (!lzw_output_code(&state, prefix))
+ return E_FAIL;
+
+ if (lzw_dict_add(&state, prefix, suffix) == -1)
+ {
+ if (!lzw_output_clear_code(&state))
+ return E_FAIL;
+ lzw_dict_reset(&state);
+ }
+
+ prefix = suffix;
+ }
+ else
+ prefix = code;
+ }
+
+ if (!lzw_output_code(&state, prefix))
+ return E_FAIL;
+ if (!lzw_output_eof_code(&state))
+ return E_FAIL;
+ if (!lzw_flush_bits(&state))
+ return E_FAIL;
+ }
+
+ return flush_output_data(&out) ? S_OK : E_FAIL;
+}
+
+static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
+{
+ GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+ HRESULT hr;
+
+ TRACE("%p\n", iface);
+
+ EnterCriticalSection(&This->encoder->lock);
+
+ if (This->image_data && This->lines == This->height && !This->committed)
+ {
+ BYTE gif_palette[256][3];
+
+ hr = S_OK;
+
+ if (!This->encoder->info_written)
+ {
+ struct logical_screen_descriptor lsd;
+
+ /* Logical Screen Descriptor */
+ memcpy(lsd.signature, "GIF89a", 6);
+ lsd.width = This->width;
+ lsd.height = This->height;
+ lsd.packed = 0;
+ if (This->encoder->colors)
+ lsd.packed |= 0x80; /* global color table flag */
+ lsd.packed |= 0x07 << 4; /* color resolution */
+ lsd.packed |= 0x07; /* global color table size */
+ lsd.background_color_index = 0; /* FIXME */
+ lsd.pixel_aspect_ratio = 0;
+ hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
+ if (hr == S_OK && This->encoder->colors)
+ {
+ UINT i;
+
+ /* Global Color Table */
+ memset(gif_palette, 0, sizeof(gif_palette));
+ for (i = 0; i < This->encoder->colors; i++)
+ {
+ gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
+ gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
+ gif_palette[i][2] = This->encoder->palette[i] & 0xff;
+ }
+ hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
+ }
+
+ /* FIXME: write GCE, APE, etc. GIF extensions */
+
+ if (hr == S_OK)
+ This->encoder->info_written = TRUE;
+ }
+
+ if (hr == S_OK)
+ {
+ char image_separator = 0x2c;
+
+ hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
+ if (hr == S_OK)
+ {
+ struct image_descriptor imd;
+
+ /* Image Descriptor */
+ imd.left = 0;
+ imd.top = 0;
+ imd.width = This->width;
+ imd.height = This->height;
+ imd.packed = 0;
+ if (This->colors)
+ {
+ imd.packed |= 0x80; /* local color table flag */
+ imd.packed |= 0x07; /* local color table size */
+ }
+ /* FIXME: interlace flag */
+ hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
+ if (hr == S_OK && This->colors)
+ {
+ UINT i;
+
+ /* Local Color Table */
+ memset(gif_palette, 0, sizeof(gif_palette));
+ for (i = 0; i < This->colors; i++)
+ {
+ gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
+ gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
+ gif_palette[i][2] = This->palette[i] & 0xff;
+ }
+ hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
+ if (hr == S_OK)
+ {
+ /* Image Data */
+ hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
+ if (hr == S_OK)
+ This->committed = TRUE;
+ }
+ }
+ }
+ }
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->encoder->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
+{
+ FIXME("%p, %p: stub\n", iface, writer);
+ return E_NOTIMPL;
+}
+
+static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
+{
+ GifFrameEncode_QueryInterface,
+ GifFrameEncode_AddRef,
+ GifFrameEncode_Release,
+ GifFrameEncode_Initialize,
+ GifFrameEncode_SetSize,
+ GifFrameEncode_SetResolution,
+ GifFrameEncode_SetPixelFormat,
+ GifFrameEncode_SetColorContexts,
+ GifFrameEncode_SetPalette,
+ GifFrameEncode_SetThumbnail,
+ GifFrameEncode_WritePixels,
+ GifFrameEncode_WriteSource,
+ GifFrameEncode_Commit,
+ GifFrameEncode_GetMetadataQueryWriter
+};
+
+static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
+{
+ TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
+
+ if (!ppv) return E_INVALIDARG;
+
+ if (IsEqualIID(&IID_IUnknown, iid) ||
+ IsEqualIID(&IID_IWICBitmapEncoder, iid))
+ {
+ IWICBitmapEncoder_AddRef(iface);
+ *ppv = iface;
+ return S_OK;
+ }
+
+ *ppv = NULL;
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+ return ref;
+}
+
+static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("%p -> %u\n", iface, ref);
+
+ if (!ref)
+ {
+ if (This->stream) IStream_Release(This->stream);
+ This->lock.DebugInfo->Spare[0] = 0;
+ DeleteCriticalSection(&This->lock);
+ HeapFree(GetProcessHeap(), 0, This);
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%#x\n", iface, stream, option);
+
+ if (!stream) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (!This->initialized)
+ {
+ IStream_AddRef(stream);
+ This->stream = stream;
+ This->initialized = TRUE;
+ hr = S_OK;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
+{
+ if (!format) return E_INVALIDARG;
+
+ *format = GUID_ContainerFormatGif;
+ return S_OK;
+}
+
+static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
+{
+ IWICComponentInfo *comp_info;
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, info);
+
+ if (!info) return E_INVALIDARG;
+
+ hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
+ if (hr == S_OK)
+ {
+ hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
+ IWICComponentInfo_Release(comp_info);
+ }
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
+{
+ FIXME("%p,%u,%p: stub\n", iface, count, context);
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p\n", iface, palette);
+
+ if (!palette) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized)
+ hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
+ else
+ hr = WINCODEC_ERR_NOTINITIALIZED;
+
+ LeaveCriticalSection(&This->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
+{
+ TRACE("%p,%p\n", iface, thumbnail);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
+{
+ TRACE("%p,%p\n", iface, preview);
+ return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p,%p,%p\n", iface, frame, options);
+
+ if (!frame) return E_INVALIDARG;
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized && !This->committed)
+ {
+ GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
+ if (ret)
+ {
+ This->n_frames++;
+
+ ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
+ ret->ref = 1;
+ ret->encoder = This;
+ ret->initialized = FALSE;
+ ret->interlace = FALSE; /* FIXME: read from the properties */
+ ret->committed = FALSE;
+ ret->width = 0;
+ ret->height = 0;
+ ret->lines = 0;
+ ret->xres = 0.0;
+ ret->yres = 0.0;
+ ret->colors = 0;
+ ret->image_data = NULL;
+ IWICBitmapEncoder_AddRef(iface);
+ *frame = &ret->IWICBitmapFrameEncode_iface;
+
+ hr = S_OK;
+
+ if (options)
+ {
+ hr = CreatePropertyBag2(NULL, 0, options);
+ if (hr != S_OK)
+ {
+ IWICBitmapFrameEncode_Release(*frame);
+ *frame = NULL;
+ }
+ }
+ }
+ else
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+
+ return hr;
+
+}
+
+static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
+{
+ GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
+ HRESULT hr;
+
+ TRACE("%p\n", iface);
+
+ EnterCriticalSection(&This->lock);
+
+ if (This->initialized && !This->committed)
+ {
+ char gif_trailer = 0x3b;
+
+ /* FIXME: write text, comment GIF extensions */
+
+ hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
+ if (hr == S_OK)
+ This->committed = TRUE;
+ }
+ else
+ hr = WINCODEC_ERR_WRONGSTATE;
+
+ LeaveCriticalSection(&This->lock);
+ return hr;
+}
+
+static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
+{
+ FIXME("%p,%p: stub\n", iface, writer);
+ return E_NOTIMPL;
+}
+
+static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
+{
+ GifEncoder_QueryInterface,
+ GifEncoder_AddRef,
+ GifEncoder_Release,
+ GifEncoder_Initialize,
+ GifEncoder_GetContainerFormat,
+ GifEncoder_GetEncoderInfo,
+ GifEncoder_SetColorContexts,
+ GifEncoder_SetPalette,
+ GifEncoder_SetThumbnail,
+ GifEncoder_SetPreview,
+ GifEncoder_CreateNewFrame,
+ GifEncoder_Commit,
+ GifEncoder_GetMetadataQueryWriter
+};
+
+HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
+{
+ GifEncoder *This;
+ HRESULT ret;
+
+ TRACE("%s,%p\n", debugstr_guid(iid), ppv);
+
+ *ppv = NULL;
+
+ This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+ if (!This) return E_OUTOFMEMORY;
+
+ This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
+ This->ref = 1;
+ This->stream = NULL;
+ InitializeCriticalSection(&This->lock);
+ This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
+ This->initialized = FALSE;
+ This->info_written = FALSE;
+ This->committed = FALSE;
+ This->n_frames = 0;
+ This->colors = 0;
+
+ ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
+ IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
+
+ return ret;
+}
diff --git a/dlls/windowscodecs/regsvr.c b/dlls/windowscodecs/regsvr.c
index 4750ab8484..584897689d 100644
--- a/dlls/windowscodecs/regsvr.c
+++ b/dlls/windowscodecs/regsvr.c
@@ -1434,6 +1434,16 @@ static struct regsvr_encoder const encoder_list[] = {
".bmp,.dib,.rle",
bmp_encode_formats
},
+ { &CLSID_WICGifEncoder,
+ "The Wine Project",
+ "GIF Encoder",
+ "1.0.0.0",
+ &GUID_VendorMicrosoft,
+ &GUID_ContainerFormatGif,
+ "image/gif",
+ ".gif",
+ gif_formats
+ },
{ &CLSID_WICJpegEncoder,
"The Wine Project",
"JPEG Encoder",
diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h
index 48b9b06469..f7665d1173 100644
--- a/dlls/windowscodecs/wincodecs_private.h
+++ b/dlls/windowscodecs/wincodecs_private.h
@@ -143,6 +143,7 @@ extern HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN
extern HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT GifDecoder_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN;
+extern HRESULT GifEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
extern HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN;
diff --git a/dlls/windowscodecs/windowscodecs_wincodec.idl b/dlls/windowscodecs/windowscodecs_wincodec.idl
index 24d48bcb5c..3519e6c618 100644
--- a/dlls/windowscodecs/windowscodecs_wincodec.idl
+++ b/dlls/windowscodecs/windowscodecs_wincodec.idl
@@ -76,6 +76,13 @@ coclass WICBmpEncoder { interface IWICBitmapEncoder; }
]
coclass WICGifDecoder { interface IWICBitmapDecoder; }
+[
+ helpstring("WIC GIF Encoder"),
+ threading(both),
+ uuid(114f5598-0b22-40a0-86a1-c83ea495adbd)
+]
+coclass WICGifEncoder { interface IWICBitmapEncoder; }
+
[
helpstring("WIC ICO Decoder"),
threading(both),
--
2.26.2
3
2
Changes comparing to old version of this patch: return S_OK in GetFrame instead of a error code.
Signed-off-by: Ziqing Hui <zhui(a)codeweavers.com>
---
dlls/windowscodecs/ddsformat.c | 155 ++++++++++++++++++++++++++++++++-
1 file changed, 153 insertions(+), 2 deletions(-)
2
1
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v2: Don't actually write to the vtbl, in an attempt to make the test
multithread-compatible.
dlls/ddraw/tests/ddraw1.c | 70 +++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/dlls/ddraw/tests/ddraw1.c b/dlls/ddraw/tests/ddraw1.c
index 0e1f4ce85c6..4e27ecfb796 100644
--- a/dlls/ddraw/tests/ddraw1.c
+++ b/dlls/ddraw/tests/ddraw1.c
@@ -13410,6 +13410,75 @@ done:
DestroyWindow(window);
}
+static void check_vtbl_protection_(int line, const void *vtbl, SIZE_T size)
+{
+ MEMORY_BASIC_INFORMATION info;
+ SIZE_T ret = VirtualQuery(vtbl, &info, size);
+ ok_(__FILE__, line)(ret == sizeof(info), "Failed to query memory.\n");
+ ok_(__FILE__, line)(info.Protect & (PAGE_READWRITE | PAGE_WRITECOPY), "Got protection %#x.\n", info.Protect);
+}
+#define check_vtbl_protection(a) check_vtbl_protection_(__LINE__, a, sizeof(*(a)))
+
+static void test_vtbl_protection(void)
+{
+ PALETTEENTRY palette_entries[256];
+ IDirectDrawSurface7 *surface7;
+ IDirectDrawSurface4 *surface4;
+ IDirectDrawSurface3 *surface3;
+ IDirectDrawSurface2 *surface2;
+ IDirectDrawSurface *surface1;
+ IDirectDrawPalette *palette;
+ DDSURFACEDESC surface_desc;
+ IDirectDraw *ddraw;
+ ULONG refcount;
+ HWND window;
+ HRESULT hr;
+
+ window = create_window();
+ ddraw = create_ddraw();
+ ok(!!ddraw, "Failed to create a ddraw object.\n");
+ hr = IDirectDraw_SetCooperativeLevel(ddraw, window, DDSCL_NORMAL);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(&surface_desc, 0, sizeof(surface_desc));
+ surface_desc.dwSize = sizeof(surface_desc);
+ surface_desc.dwFlags = DDSD_CAPS;
+ surface_desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
+ hr = IDirectDraw_CreateSurface(ddraw, &surface_desc, &surface1, NULL);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface2, (void **)&surface2);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface3, (void **)&surface3);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface4, (void **)&surface4);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+ hr = IDirectDrawSurface_QueryInterface(surface1, &IID_IDirectDrawSurface7, (void **)&surface7);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ memset(palette_entries, 0, sizeof(palette_entries));
+ hr = IDirectDraw_CreatePalette(ddraw, DDPCAPS_8BIT | DDPCAPS_ALLOW256,
+ palette_entries, &palette, NULL);
+ ok(hr == DD_OK, "Got unexpected hr %#x.\n", hr);
+
+ check_vtbl_protection(ddraw->lpVtbl);
+ check_vtbl_protection(palette->lpVtbl);
+ check_vtbl_protection(surface1->lpVtbl);
+ check_vtbl_protection(surface2->lpVtbl);
+ check_vtbl_protection(surface3->lpVtbl);
+ check_vtbl_protection(surface4->lpVtbl);
+ check_vtbl_protection(surface7->lpVtbl);
+
+ IDirectDrawPalette_Release(palette);
+ IDirectDrawSurface_Release(surface1);
+ IDirectDrawSurface2_Release(surface2);
+ IDirectDrawSurface3_Release(surface3);
+ IDirectDrawSurface4_Release(surface4);
+ IDirectDrawSurface7_Release(surface7);
+ refcount = IDirectDraw_Release(ddraw);
+ ok(!refcount, "%u references left.\n", refcount);
+ DestroyWindow(window);
+}
+
START_TEST(ddraw1)
{
DDDEVICEIDENTIFIER identifier;
@@ -13523,4 +13592,5 @@ START_TEST(ddraw1)
test_caps();
test_d32_support();
test_cursor_clipping();
+ test_vtbl_protection();
}
--
2.26.2
2
1
27 Apr '20
From: Michael Müller <michael(a)fds-team.de>
Wine-Bug: <https://bugs.winehq.org/show_bug.cgi?id=39534>
Signed-off-by: Michael Müller <michael(a)fds-team.de>
Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
dlls/ddraw/ddraw.c | 3 ++-
dlls/ddraw/surface.c | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/ddraw/ddraw.c b/dlls/ddraw/ddraw.c
index 7cfb56f45cc..b7e7e6514a8 100644
--- a/dlls/ddraw/ddraw.c
+++ b/dlls/ddraw/ddraw.c
@@ -4661,7 +4661,8 @@ static const struct IDirectDraw2Vtbl ddraw2_vtbl =
ddraw2_GetAvailableVidMem,
};
-static const struct IDirectDrawVtbl ddraw1_vtbl =
+/* Bad Mojo Redux expects this vtbl to be writable. */
+static struct IDirectDrawVtbl ddraw1_vtbl =
{
/* IUnknown */
ddraw1_QueryInterface,
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c
index c418bb7b2b3..44230838352 100644
--- a/dlls/ddraw/surface.c
+++ b/dlls/ddraw/surface.c
@@ -5613,7 +5613,8 @@ static const struct IDirectDrawSurface2Vtbl ddraw_surface2_vtbl =
ddraw_surface2_PageUnlock,
};
-static const struct IDirectDrawSurfaceVtbl ddraw_surface1_vtbl =
+/* Bad Mojo Redux expects this vtbl to be writable. */
+static struct IDirectDrawSurfaceVtbl ddraw_surface1_vtbl =
{
/* IUnknown */
ddraw_surface1_QueryInterface,
--
2.26.2
2
4
[PATCH v5 1/5] qedit: Check for S_OK when enumerating the splitter pin.
by Gabriel Ivăncescu 27 Apr '20
by Gabriel Ivăncescu 27 Apr '20
27 Apr '20
The splitter may return S_FALSE (no pins) and this caused a crash when it
somehow matched with the File Source (Async).
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
dlls/qedit/mediadet.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/qedit/mediadet.c b/dlls/qedit/mediadet.c
index eb7a519..c3891c5 100644
--- a/dlls/qedit/mediadet.c
+++ b/dlls/qedit/mediadet.c
@@ -197,7 +197,7 @@ static HRESULT find_splitter(MediaDetImpl *detector)
hr = IEnumPins_Next(enum_pins, 1, &splitter_pin, NULL);
IEnumPins_Release(enum_pins);
- if (FAILED(hr))
+ if (hr != S_OK)
goto next;
hr = IPin_Connect(source_pin, splitter_pin, NULL);
--
2.21.0
3
7
Signed-off-by: Serge Gautherie <winehq-git_serge_180711(a)gautherie.fr>
---
Cherry-pick
https://git.reactos.org/?p=reactos.git;a=commit;h=a16a37fd2d0506fed4006cb97…
---
dlls/rpcrt4/rpcrt4.spec | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dlls/rpcrt4/rpcrt4.spec b/dlls/rpcrt4/rpcrt4.spec
index 0492776..9c85037 100644
--- a/dlls/rpcrt4/rpcrt4.spec
+++ b/dlls/rpcrt4/rpcrt4.spec
@@ -276,7 +276,7 @@
@ stdcall NdrSendReceive(ptr ptr)
@ stdcall NdrServerCall2(ptr)
@ stdcall NdrServerCall(ptr)
-@ stdcall NdrServerCallAll(ptr)
+@ stdcall -arch=x86_64 NdrServerCallAll(ptr)
@ stdcall NdrServerContextMarshall(ptr ptr ptr)
@ stdcall NdrServerContextNewMarshall(ptr ptr ptr ptr) # wxp
@ stdcall NdrServerContextNewUnmarshall(ptr ptr) # wxp
--
2.10.0.windows.1
3
3
27 Apr '20
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49011
Signed-off-by: Jacek Caban <jacek(a)codeweavers.com>
---
dlls/kernel32/tests/thread.c | 15 +++++++++++++++
server/thread.c | 2 +-
2 files changed, 16 insertions(+), 1 deletion(-)
2
2
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/context_vk.c | 194 ++++++++++++++++++++++
dlls/wined3d/texture.c | 294 ++++++++++++++++++++++++++++++++-
dlls/wined3d/view.c | 2 +-
dlls/wined3d/wined3d_private.h | 49 +++++-
4 files changed, 531 insertions(+), 8 deletions(-)
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index f5a321b076c..f4a52fb9c2f 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -296,6 +296,31 @@ static struct wined3d_retired_object_vk *wined3d_context_vk_get_retired_object_v
return &retired->objects[retired->count++];
}
+void wined3d_context_vk_destroy_framebuffer(struct wined3d_context_vk *context_vk,
+ VkFramebuffer vk_framebuffer, uint64_t command_buffer_id)
+{
+ struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+ const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+ struct wined3d_retired_object_vk *o;
+
+ if (context_vk->completed_command_buffer_id > command_buffer_id)
+ {
+ VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, vk_framebuffer, NULL));
+ TRACE("Destroyed framebuffer 0x%s.\n", wine_dbgstr_longlong(vk_framebuffer));
+ return;
+ }
+
+ if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk)))
+ {
+ ERR("Leaking framebuffer 0x%s.\n", wine_dbgstr_longlong(vk_framebuffer));
+ return;
+ }
+
+ o->type = WINED3D_RETIRED_FRAMEBUFFER_VK;
+ o->u.vk_framebuffer = vk_framebuffer;
+ o->command_buffer_id = command_buffer_id;
+}
+
void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context_vk,
VkDeviceMemory vk_memory, uint64_t command_buffer_id)
{
@@ -538,6 +563,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
/* Nothing to do. */
break;
+ case WINED3D_RETIRED_FRAMEBUFFER_VK:
+ VK_CALL(vkDestroyFramebuffer(device_vk->vk_device, o->u.vk_framebuffer, NULL));
+ TRACE("Destroyed framebuffer 0x%s.\n", wine_dbgstr_longlong(o->u.vk_framebuffer));
+ break;
+
case WINED3D_RETIRED_MEMORY_VK:
VK_CALL(vkFreeMemory(device_vk->vk_device, o->u.vk_memory, NULL));
TRACE("Freed memory 0x%s.\n", wine_dbgstr_longlong(o->u.vk_memory));
@@ -599,6 +629,158 @@ static void wined3d_context_vk_destroy_bo_slab(struct wine_rb_entry *entry, void
}
}
+static void wined3d_render_pass_key_vk_init(struct wined3d_render_pass_key_vk *key,
+ const struct wined3d_fb_state *fb, unsigned int rt_count)
+{
+ struct wined3d_render_pass_attachment_vk *a;
+ struct wined3d_rendertarget_view *view;
+ unsigned int i;
+
+ memset(key, 0, sizeof(*key));
+
+ for (i = 0; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]) || view->format->id == WINED3DFMT_NULL)
+ continue;
+
+ a = &key->rt[i];
+ a->vk_format = wined3d_format_vk(view->format)->vk_format;
+ a->vk_samples = max(1, wined3d_resource_get_sample_count(view->resource));
+ a->vk_layout = wined3d_texture_vk(wined3d_texture_from_resource(view->resource))->layout;
+ key->rt_mask |= 1u << i;
+ }
+}
+
+static void wined3d_render_pass_vk_cleanup(struct wined3d_render_pass_vk *pass,
+ struct wined3d_context_vk *context_vk)
+{
+ struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+ const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+
+ VK_CALL(vkDestroyRenderPass(device_vk->vk_device, pass->vk_render_pass, NULL));
+}
+
+static bool wined3d_render_pass_vk_init(struct wined3d_render_pass_vk *pass,
+ struct wined3d_context_vk *context_vk, const struct wined3d_render_pass_key_vk *key)
+{
+ struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+ VkAttachmentReference attachment_references[WINED3D_MAX_RENDER_TARGETS];
+ VkAttachmentDescription attachments[WINED3D_MAX_RENDER_TARGETS + 1];
+ const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+ const struct wined3d_render_pass_attachment_vk *a;
+ unsigned int attachment_count, rt_count, i;
+ VkAttachmentDescription *attachment;
+ VkSubpassDescription sub_pass_desc;
+ VkRenderPassCreateInfo pass_desc;
+ uint32_t mask;
+ VkResult vr;
+
+ rt_count = 0;
+ attachment_count = 0;
+ mask = key->rt_mask & ((1u << WINED3D_MAX_RENDER_TARGETS) - 1);
+ while (mask)
+ {
+ i = wined3d_bit_scan(&mask);
+ a = &key->rt[i];
+
+ attachment = &attachments[attachment_count];
+ attachment->flags = 0;
+ attachment->format = a->vk_format;
+ attachment->samples = a->vk_samples;
+ attachment->loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
+ attachment->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
+ attachment->stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
+ attachment->stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
+ attachment->initialLayout = a->vk_layout;
+ attachment->finalLayout = a->vk_layout;
+
+ attachment_references[i].attachment = attachment_count;
+ attachment_references[i].layout = a->vk_layout;
+
+ ++attachment_count;
+ rt_count = i + 1;
+ }
+
+ mask = ~key->rt_mask & ((1u << rt_count) - 1);
+ while (mask)
+ {
+ i = wined3d_bit_scan(&mask);
+ attachment_references[i].attachment = VK_ATTACHMENT_UNUSED;
+ attachment_references[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
+ }
+
+ sub_pass_desc.flags = 0;
+ sub_pass_desc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
+ sub_pass_desc.inputAttachmentCount = 0;
+ sub_pass_desc.pInputAttachments = NULL;
+ sub_pass_desc.colorAttachmentCount = rt_count;
+ sub_pass_desc.pColorAttachments = attachment_references;
+ sub_pass_desc.pResolveAttachments = NULL;
+ sub_pass_desc.pDepthStencilAttachment = NULL;
+ sub_pass_desc.preserveAttachmentCount = 0;
+ sub_pass_desc.pPreserveAttachments = NULL;
+
+ pass_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
+ pass_desc.pNext = NULL;
+ pass_desc.flags = 0;
+ pass_desc.attachmentCount = attachment_count;
+ pass_desc.pAttachments = attachments;
+ pass_desc.subpassCount = 1;
+ pass_desc.pSubpasses = &sub_pass_desc;
+ pass_desc.dependencyCount = 0;
+ pass_desc.pDependencies = NULL;
+
+ pass->key = *key;
+ if ((vr = VK_CALL(vkCreateRenderPass(device_vk->vk_device,
+ &pass_desc, NULL, &pass->vk_render_pass))) < 0)
+ {
+ WARN("Failed to create Vulkan render pass, vr %d.\n", vr);
+ return false;
+ }
+
+ return true;
+}
+
+VkRenderPass wined3d_context_vk_get_render_pass(struct wined3d_context_vk *context_vk,
+ const struct wined3d_fb_state *fb, unsigned int rt_count)
+{
+ struct wined3d_render_pass_key_vk key;
+ struct wined3d_render_pass_vk *pass;
+ struct wine_rb_entry *entry;
+
+ wined3d_render_pass_key_vk_init(&key, fb, rt_count);
+ if ((entry = wine_rb_get(&context_vk->render_passes, &key)))
+ return WINE_RB_ENTRY_VALUE(entry, struct wined3d_render_pass_vk, entry)->vk_render_pass;
+
+ if (!(pass = heap_alloc(sizeof(*pass))))
+ return VK_NULL_HANDLE;
+
+ if (!wined3d_render_pass_vk_init(pass, context_vk, &key))
+ {
+ heap_free(pass);
+ return VK_NULL_HANDLE;
+ }
+
+ if (wine_rb_put(&context_vk->render_passes, &pass->key, &pass->entry) == -1)
+ {
+ ERR("Failed to insert render pass.\n");
+ wined3d_render_pass_vk_cleanup(pass, context_vk);
+ heap_free(pass);
+ return VK_NULL_HANDLE;
+ }
+
+ return pass->vk_render_pass;
+}
+
+static void wined3d_context_vk_destroy_render_pass(struct wine_rb_entry *entry, void *ctx)
+{
+ struct wined3d_render_pass_vk *pass = WINE_RB_ENTRY_VALUE(entry,
+ struct wined3d_render_pass_vk, entry);
+
+ wined3d_render_pass_vk_cleanup(pass, ctx);
+ heap_free(pass);
+}
+
void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
{
struct wined3d_command_buffer_vk *buffer = &context_vk->current_command_buffer;
@@ -620,6 +802,8 @@ void wined3d_context_vk_cleanup(struct wined3d_context_vk *context_vk)
heap_free(context_vk->submitted.buffers);
heap_free(context_vk->retired.objects);
+ wine_rb_destroy(&context_vk->render_passes, wined3d_context_vk_destroy_render_pass, context_vk);
+
wined3d_context_cleanup(&context_vk->c);
}
@@ -784,6 +968,15 @@ void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk,
VK_CALL(vkCmdPipelineBarrier(vk_command_buffer, src_stage_mask, dst_stage_mask, 0, 0, NULL, 0, NULL, 1, &barrier));
}
+static int wined3d_render_pass_vk_compare(const void *key, const struct wine_rb_entry *entry)
+{
+ const struct wined3d_render_pass_key_vk *k = key;
+ const struct wined3d_render_pass_vk *pass = WINE_RB_ENTRY_VALUE(entry,
+ const struct wined3d_render_pass_vk, entry);
+
+ return memcmp(k, &pass->key, sizeof(*k));
+}
+
static int wined3d_bo_slab_vk_compare(const void *key, const struct wine_rb_entry *entry)
{
const struct wined3d_bo_slab_vk *slab = WINE_RB_ENTRY_VALUE(entry, const struct wined3d_bo_slab_vk, entry);
@@ -824,6 +1017,7 @@ HRESULT wined3d_context_vk_init(struct wined3d_context_vk *context_vk, struct wi
}
context_vk->current_command_buffer.id = 1;
+ wine_rb_init(&context_vk->render_passes, wined3d_render_pass_vk_compare);
wine_rb_init(&context_vk->bo_slab_available, wined3d_bo_slab_vk_compare);
return WINED3D_OK;
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 0e39ad55a8c..ef5f3cd48e5 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -4484,6 +4484,57 @@ HRESULT wined3d_texture_no3d_init(struct wined3d_texture *texture_no3d, struct w
flags, device, parent, parent_ops, &texture_no3d[1], &wined3d_texture_no3d_ops);
}
+const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk,
+ struct wined3d_context_vk *context_vk)
+{
+ const struct wined3d_format_vk *format_vk;
+ const struct wined3d_vk_info *vk_info;
+ struct wined3d_device_vk *device_vk;
+ VkImageViewCreateInfo create_info;
+ uint32_t flags = 0;
+ VkResult vr;
+
+ if (texture_vk->default_image_info.imageView)
+ return &texture_vk->default_image_info;
+
+ format_vk = wined3d_format_vk(texture_vk->t.resource.format);
+ device_vk = wined3d_device_vk(texture_vk->t.resource.device);
+ vk_info = context_vk->vk_info;
+
+ if (texture_vk->t.layer_count > 1)
+ flags |= WINED3D_VIEW_TEXTURE_ARRAY;
+
+ wined3d_texture_vk_prepare_texture(texture_vk, context_vk);
+ create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.image = texture_vk->vk_image;
+ create_info.viewType = vk_image_view_type_from_wined3d(texture_vk->t.resource.type, flags);
+ create_info.format = format_vk->vk_format;
+ create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
+ create_info.subresourceRange.baseMipLevel = 0;
+ create_info.subresourceRange.levelCount = texture_vk->t.level_count;
+ create_info.subresourceRange.baseArrayLayer = 0;
+ create_info.subresourceRange.layerCount = texture_vk->t.layer_count;
+ if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info,
+ NULL, &texture_vk->default_image_info.imageView))) < 0)
+ {
+ ERR("Failed to create Vulkan image view, vr %s.\n", wined3d_debug_vkresult(vr));
+ return NULL;
+ }
+
+ TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(texture_vk->default_image_info.imageView));
+
+ texture_vk->default_image_info.sampler = VK_NULL_HANDLE;
+ texture_vk->default_image_info.imageLayout = texture_vk->layout;
+
+ return &texture_vk->default_image_info;
+}
+
static void wined3d_texture_vk_upload_data(struct wined3d_context *context,
const struct wined3d_const_bo_address *src_bo_addr, const struct wined3d_format *src_format,
const struct wined3d_box *src_box, unsigned int src_row_pitch, unsigned int src_slice_pitch,
@@ -5042,6 +5093,13 @@ static void wined3d_texture_vk_unload_location(struct wined3d_texture *texture,
switch (location)
{
case WINED3D_LOCATION_TEXTURE_RGB:
+ if (texture_vk->default_image_info.imageView)
+ {
+ wined3d_context_vk_destroy_image_view(context_vk,
+ texture_vk->default_image_info.imageView, texture_vk->command_buffer_id);
+ texture_vk->default_image_info.imageView = VK_NULL_HANDLE;
+ }
+
if (texture_vk->vk_image)
{
wined3d_context_vk_destroy_image(context_vk, texture_vk->vk_image, texture_vk->command_buffer_id);
@@ -5419,7 +5477,7 @@ static void ffp_blitter_clear_rendertargets(struct wined3d_device *device, unsig
context_release(context);
}
-static bool ffp_blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
+static bool blitter_use_cpu_clear(struct wined3d_rendertarget_view *view)
{
struct wined3d_resource *resource;
struct wined3d_texture *texture;
@@ -5458,7 +5516,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
if (!(view = fb->render_targets[i]))
continue;
- if (ffp_blitter_use_cpu_clear(view)
+ if (blitter_use_cpu_clear(view)
|| (!(view->resource->bind_flags & WINED3D_BIND_RENDER_TARGET)
&& (wined3d_settings.offscreen_rendering_mode != ORM_FBO
|| !(view->format_flags & WINED3DFMT_FLAG_FBO_ATTACHABLE))))
@@ -5478,7 +5536,7 @@ static void ffp_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_de
if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && (view = fb->depth_stencil)
&& (!view->format->depth_size || (flags & WINED3DCLEAR_ZBUFFER))
&& (!view->format->stencil_size || (flags & WINED3DCLEAR_STENCIL))
- && ffp_blitter_use_cpu_clear(view))
+ && blitter_use_cpu_clear(view))
{
next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
@@ -5978,17 +6036,243 @@ static void vk_blitter_destroy(struct wined3d_blitter *blitter, struct wined3d_c
heap_free(blitter);
}
+static inline VkImageView wined3d_rendertarget_view_vk_get_image_view(struct wined3d_rendertarget_view_vk *rtv_vk,
+ struct wined3d_context_vk *context_vk)
+{
+ struct wined3d_texture_vk *texture_vk;
+
+ if (rtv_vk->vk_image_view)
+ return rtv_vk->vk_image_view;
+
+ texture_vk = wined3d_texture_vk(wined3d_texture_from_resource(rtv_vk->v.resource));
+ return wined3d_texture_vk_get_default_image_info(texture_vk, context_vk)->imageView;
+}
+
+static void vk_blitter_clear_rendertargets(struct wined3d_context_vk *context_vk, unsigned int rt_count,
+ const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects, const RECT *draw_rect,
+ uint32_t flags, const struct wined3d_color *colour, float depth, unsigned int stencil)
+{
+ VkClearValue clear_values[WINED3D_MAX_RENDER_TARGETS];
+ VkImageView views[WINED3D_MAX_RENDER_TARGETS];
+ struct wined3d_rendertarget_view_vk *rtv_vk;
+ struct wined3d_rendertarget_view *view;
+ const struct wined3d_vk_info *vk_info;
+ struct wined3d_texture_vk *texture_vk;
+ struct wined3d_device_vk *device_vk;
+ VkCommandBuffer vk_command_buffer;
+ VkRenderPassBeginInfo begin_desc;
+ unsigned int i, attachment_count;
+ VkFramebufferCreateInfo fb_desc;
+ VkFramebuffer vk_framebuffer;
+ VkRenderPass vk_render_pass;
+ unsigned int layer_count;
+ VkClearColorValue *c;
+ VkResult vr;
+ RECT r;
+
+ TRACE("context_vk %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
+ "draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
+ context_vk, rt_count, fb, rect_count, clear_rects,
+ wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
+
+ device_vk = wined3d_device_vk(context_vk->c.device);
+ vk_info = context_vk->vk_info;
+
+ for (i = 0, attachment_count = 0, layer_count = 1; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]))
+ continue;
+
+ if (!is_full_clear(view, draw_rect, clear_rects))
+ wined3d_rendertarget_view_load_location(view, &context_vk->c, view->resource->draw_binding);
+ else
+ wined3d_rendertarget_view_prepare_location(view, &context_vk->c, view->resource->draw_binding);
+ wined3d_rendertarget_view_validate_location(view, view->resource->draw_binding);
+ wined3d_rendertarget_view_invalidate_location(view, ~view->resource->draw_binding);
+
+ rtv_vk = wined3d_rendertarget_view_vk(view);
+ views[attachment_count] = wined3d_rendertarget_view_vk_get_image_view(rtv_vk, context_vk);
+
+ c = &clear_values[attachment_count].color;
+ if (view->format_flags & WINED3DFMT_FLAG_INTEGER)
+ {
+ c->int32[0] = colour->r;
+ c->int32[1] = colour->g;
+ c->int32[2] = colour->b;
+ c->int32[3] = colour->a;
+ }
+ else
+ {
+ c->float32[0] = colour->r;
+ c->float32[1] = colour->g;
+ c->float32[2] = colour->b;
+ c->float32[3] = colour->a;
+ }
+
+ if (view->layer_count > layer_count)
+ layer_count = view->layer_count;
+
+ ++attachment_count;
+ }
+
+ if (!(vk_render_pass = wined3d_context_vk_get_render_pass(context_vk, fb, rt_count)))
+ {
+ ERR("Failed to get render pass.\n");
+ return;
+ }
+
+ if (!(vk_command_buffer = wined3d_context_vk_get_command_buffer(context_vk)))
+ {
+ ERR("Failed to get command buffer.\n");
+ return;
+ }
+
+ fb_desc.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
+ fb_desc.pNext = NULL;
+ fb_desc.flags = 0;
+ fb_desc.renderPass = vk_render_pass;
+ fb_desc.attachmentCount = attachment_count;
+ fb_desc.pAttachments = views;
+ fb_desc.width = draw_rect->right - draw_rect->left;
+ fb_desc.height = draw_rect->bottom - draw_rect->top;
+ fb_desc.layers = layer_count;
+ if ((vr = VK_CALL(vkCreateFramebuffer(device_vk->vk_device, &fb_desc, NULL, &vk_framebuffer))) < 0)
+ {
+ ERR("Failed to create Vulkan framebuffer, vr %s.\n", wined3d_debug_vkresult(vr));
+ return;
+ }
+
+ begin_desc.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
+ begin_desc.pNext = NULL;
+ begin_desc.renderPass = vk_render_pass;
+ begin_desc.framebuffer = vk_framebuffer;
+ begin_desc.clearValueCount = attachment_count;
+ begin_desc.pClearValues = clear_values;
+
+ for (i = 0; i < rect_count; ++i)
+ {
+ r.left = max(clear_rects[i].left, draw_rect->left);
+ r.top = max(clear_rects[i].top, draw_rect->top);
+ r.right = min(clear_rects[i].right, draw_rect->right);
+ r.bottom = min(clear_rects[i].bottom, draw_rect->bottom);
+
+ if (r.left >= r.right || r.top >= r.bottom)
+ continue;
+
+ begin_desc.renderArea.offset.x = r.left;
+ begin_desc.renderArea.offset.y = r.top;
+ begin_desc.renderArea.extent.width = r.right - r.left;
+ begin_desc.renderArea.extent.height = r.bottom - r.top;
+ VK_CALL(vkCmdBeginRenderPass(vk_command_buffer, &begin_desc, VK_SUBPASS_CONTENTS_INLINE));
+ VK_CALL(vkCmdEndRenderPass(vk_command_buffer));
+ }
+
+ wined3d_context_vk_destroy_framebuffer(context_vk, vk_framebuffer, context_vk->current_command_buffer.id);
+
+ for (i = 0; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]))
+ continue;
+
+ wined3d_context_vk_reference_rendertarget_view(context_vk, wined3d_rendertarget_view_vk(view));
+ texture_vk = wined3d_texture_vk(wined3d_texture_from_resource(view->resource));
+ wined3d_context_vk_image_barrier(context_vk, vk_command_buffer,
+ VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
+ VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
+ vk_access_mask_from_bind_flags(texture_vk->t.resource.bind_flags),
+ texture_vk->layout, texture_vk->layout,
+ texture_vk->vk_image, VK_IMAGE_ASPECT_COLOR_BIT);
+ }
+}
+
static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_device *device,
unsigned int rt_count, const struct wined3d_fb_state *fb, unsigned int rect_count, const RECT *clear_rects,
const RECT *draw_rect, DWORD flags, const struct wined3d_color *colour, float depth, DWORD stencil)
{
+ struct wined3d_device_vk *device_vk = wined3d_device_vk(device);
+ struct wined3d_rendertarget_view *view, *previous = NULL;
+ struct wined3d_context_vk *context_vk;
+ bool have_identical_size = true;
+ struct wined3d_fb_state tmp_fb;
+ unsigned int next_rt_count = 0;
struct wined3d_blitter *next;
+ uint32_t next_flags = 0;
+ unsigned int i;
TRACE("blitter %p, device %p, rt_count %u, fb %p, rect_count %u, clear_rects %p, "
"draw_rect %s, flags %#x, colour %s, depth %.8e, stencil %#x.\n",
blitter, device, rt_count, fb, rect_count, clear_rects,
wine_dbgstr_rect(draw_rect), flags, debug_color(colour), depth, stencil);
+ if (!rect_count)
+ {
+ rect_count = 1;
+ clear_rects = draw_rect;
+ }
+
+ if (flags & WINED3DCLEAR_TARGET)
+ {
+ for (i = 0; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]))
+ continue;
+
+ if (blitter_use_cpu_clear(view))
+ {
+ next_flags |= WINED3DCLEAR_TARGET;
+ flags &= ~WINED3DCLEAR_TARGET;
+ next_rt_count = rt_count;
+ rt_count = 0;
+ break;
+ }
+ }
+ }
+
+ if ((flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL)) && fb->depth_stencil)
+ {
+ next_flags |= flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
+ flags &= ~(WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL);
+ }
+
+ if (flags)
+ {
+ context_vk = wined3d_context_vk(context_acquire(&device_vk->d, NULL, 0));
+
+ for (i = 0; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]))
+ continue;
+
+ if (previous && (previous->width != view->width || previous->height != view->height))
+ have_identical_size = false;
+ previous = view;
+ }
+
+ if (have_identical_size)
+ {
+ vk_blitter_clear_rendertargets(context_vk, rt_count, fb, rect_count,
+ clear_rects, draw_rect, flags, colour, depth, stencil);
+ }
+ else
+ {
+ for (i = 0; i < rt_count; ++i)
+ {
+ if (!(view = fb->render_targets[i]))
+ continue;
+
+ tmp_fb.render_targets[0] = view;
+ tmp_fb.depth_stencil = NULL;
+ vk_blitter_clear_rendertargets(context_vk, 1, &tmp_fb, rect_count,
+ clear_rects, draw_rect, WINED3DCLEAR_TARGET, colour, depth, stencil);
+ }
+ }
+
+ context_release(&context_vk->c);
+ }
+
+ if (!next_flags)
+ return;
+
if (!(next = blitter->next))
{
ERR("No blitter to handle clear.\n");
@@ -5996,8 +6280,8 @@ static void vk_blitter_clear(struct wined3d_blitter *blitter, struct wined3d_dev
}
TRACE("Forwarding to blitter %p.\n", next);
- next->ops->blitter_clear(next, device, rt_count, fb, rect_count,
- clear_rects, draw_rect, flags, colour, depth, stencil);
+ next->ops->blitter_clear(next, device, next_rt_count, fb, rect_count,
+ clear_rects, draw_rect, next_flags, colour, depth, stencil);
}
static bool vk_blitter_blit_supported(enum wined3d_blit_op op, const struct wined3d_context *context,
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
index 438d9a8b18f..fee64bd47d2 100644
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -621,7 +621,7 @@ HRESULT wined3d_rendertarget_view_gl_init(struct wined3d_rendertarget_view_gl *v
return hr;
}
-static VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
+VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
{
switch (type)
{
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 43bdb26c936..dd8e03d35d9 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -300,6 +300,7 @@ extern const GLenum magLookup[WINED3D_TEXF_LINEAR + 1] DECLSPEC_HIDDEN;
GLenum wined3d_gl_compare_func(enum wined3d_cmp_func f) DECLSPEC_HIDDEN;
VkAccessFlags vk_access_mask_from_bind_flags(uint32_t bind_flags) DECLSPEC_HIDDEN;
+VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags) DECLSPEC_HIDDEN;
static inline enum wined3d_cmp_func wined3d_sanitize_cmp_func(enum wined3d_cmp_func func)
{
@@ -2223,6 +2224,7 @@ struct wined3d_command_buffer_vk
enum wined3d_retired_object_type_vk
{
WINED3D_RETIRED_FREE_VK,
+ WINED3D_RETIRED_FRAMEBUFFER_VK,
WINED3D_RETIRED_MEMORY_VK,
WINED3D_RETIRED_ALLOCATOR_BLOCK_VK,
WINED3D_RETIRED_BO_SLAB_SLICE_VK,
@@ -2237,6 +2239,7 @@ struct wined3d_retired_object_vk
union
{
struct wined3d_retired_object_vk *next;
+ VkFramebuffer vk_framebuffer;
VkDeviceMemory vk_memory;
struct wined3d_allocator_block *block;
struct
@@ -2259,6 +2262,26 @@ struct wined3d_retired_objects_vk
SIZE_T count;
};
+struct wined3d_render_pass_attachment_vk
+{
+ VkFormat vk_format;
+ VkSampleCountFlagBits vk_samples;
+ VkImageLayout vk_layout;
+};
+
+struct wined3d_render_pass_key_vk
+{
+ struct wined3d_render_pass_attachment_vk rt[WINED3D_MAX_RENDER_TARGETS];
+ uint32_t rt_mask;
+};
+
+struct wined3d_render_pass_vk
+{
+ struct wine_rb_entry entry;
+ struct wined3d_render_pass_key_vk key;
+ VkRenderPass vk_render_pass;
+};
+
struct wined3d_context_vk
{
struct wined3d_context c;
@@ -2277,6 +2300,7 @@ struct wined3d_context_vk
} submitted;
struct wined3d_retired_objects_vk retired;
+ struct wine_rb_tree render_passes;
struct wine_rb_tree bo_slab_available;
};
@@ -2296,6 +2320,8 @@ void wined3d_context_vk_destroy_allocator_block(struct wined3d_context_vk *conte
struct wined3d_allocator_block *block, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk,
const struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
+void wined3d_context_vk_destroy_framebuffer(struct wined3d_context_vk *context_vk,
+ VkFramebuffer vk_framebuffer, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk,
VkImage vk_image, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk,
@@ -2303,6 +2329,8 @@ void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk
void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context_vk,
VkDeviceMemory vk_memory, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
+VkRenderPass wined3d_context_vk_get_render_pass(struct wined3d_context_vk *context_vk,
+ const struct wined3d_fb_state *fb, unsigned int rt_count) DECLSPEC_HIDDEN;
void wined3d_context_vk_image_barrier(struct wined3d_context_vk *context_vk,
VkCommandBuffer vk_command_buffer, VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask,
VkAccessFlags src_access_mask, VkAccessFlags dst_access_mask, VkImageLayout old_layout,
@@ -3996,6 +4024,8 @@ struct wined3d_texture_vk
VkDeviceMemory vk_memory;
enum VkImageLayout layout;
uint64_t command_buffer_id;
+
+ VkDescriptorImageInfo default_image_info;
};
static inline struct wined3d_texture_vk *wined3d_texture_vk(struct wined3d_texture *texture)
@@ -4003,6 +4033,8 @@ static inline struct wined3d_texture_vk *wined3d_texture_vk(struct wined3d_textu
return CONTAINING_RECORD(texture, struct wined3d_texture_vk, t);
}
+const VkDescriptorImageInfo *wined3d_texture_vk_get_default_image_info(struct wined3d_texture_vk *texture_vk,
+ struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
@@ -5490,17 +5522,30 @@ static inline void wined3d_context_copy_bo_address(struct wined3d_context *conte
context->device->adapter->adapter_ops->adapter_copy_bo_address(context, dst, src, size);
}
-static inline void wined3d_context_vk_reference_bo(struct wined3d_context_vk *context_vk, struct wined3d_bo_vk *bo)
+static inline void wined3d_context_vk_reference_bo(const struct wined3d_context_vk *context_vk,
+ struct wined3d_bo_vk *bo)
{
bo->command_buffer_id = context_vk->current_command_buffer.id;
}
-static inline void wined3d_context_vk_reference_texture(struct wined3d_context_vk *context_vk,
+static inline void wined3d_context_vk_reference_texture(const struct wined3d_context_vk *context_vk,
struct wined3d_texture_vk *texture_vk)
{
texture_vk->command_buffer_id = context_vk->current_command_buffer.id;
}
+static inline void wined3d_context_vk_reference_rendertarget_view(const struct wined3d_context_vk *context_vk,
+ struct wined3d_rendertarget_view_vk *rtv_vk)
+{
+ struct wined3d_resource *resource = rtv_vk->v.resource;
+
+ if (resource->type == WINED3D_RTYPE_BUFFER)
+ wined3d_context_vk_reference_bo(context_vk, &wined3d_buffer_vk(buffer_from_resource(resource))->bo);
+ else
+ wined3d_context_vk_reference_texture(context_vk, wined3d_texture_vk(texture_from_resource(resource)));
+ rtv_vk->command_buffer_id = context_vk->current_command_buffer.id;
+}
+
static inline BOOL wined3d_dsv_srv_conflict(const struct wined3d_rendertarget_view *dsv,
const struct wined3d_format *srv_format)
{
--
2.20.1
1
0
27 Apr '20
Signed-off-by: Henri Verbeet <hverbeet(a)codeweavers.com>
---
dlls/wined3d/adapter_vk.c | 59 ++++++++++++++-
dlls/wined3d/context_vk.c | 30 ++++++++
dlls/wined3d/texture.c | 4 +-
dlls/wined3d/view.c | 128 ++++++++++++++++++++++++++++++++-
dlls/wined3d/wined3d_private.h | 9 +++
5 files changed, 226 insertions(+), 4 deletions(-)
diff --git a/dlls/wined3d/adapter_vk.c b/dlls/wined3d/adapter_vk.c
index 16a23a5fec8..1641de78522 100644
--- a/dlls/wined3d/adapter_vk.c
+++ b/dlls/wined3d/adapter_vk.c
@@ -1200,6 +1200,63 @@ static HRESULT adapter_vk_create_rendertarget_view(const struct wined3d_view_des
return hr;
}
+struct wined3d_view_vk_destroy_ctx
+{
+ struct wined3d_device_vk *device_vk;
+ VkImageView *vk_image_view;
+ uint64_t *command_buffer_id;
+ void *object;
+ struct wined3d_view_vk_destroy_ctx *free;
+};
+
+static void wined3d_view_vk_destroy_object(void *object)
+{
+ struct wined3d_view_vk_destroy_ctx *ctx = object;
+ const struct wined3d_vk_info *vk_info;
+ struct wined3d_device_vk *device_vk;
+
+ device_vk = ctx->device_vk;
+ vk_info = &wined3d_adapter_vk(device_vk->d.adapter)->vk_info;
+
+ if (ctx->vk_image_view)
+ {
+ struct wined3d_context *context;
+
+ if (!(context = context_acquire(&device_vk->d, NULL, 0)))
+ {
+ VK_CALL(vkDestroyImageView(device_vk->vk_device, *ctx->vk_image_view, NULL));
+ TRACE("Destroyed image view 0x%s.\n", wine_dbgstr_longlong(*ctx->vk_image_view));
+ }
+ else
+ {
+ wined3d_context_vk_destroy_image_view(wined3d_context_vk(context),
+ *ctx->vk_image_view, *ctx->command_buffer_id);
+ context_release(context);
+ }
+ }
+
+ heap_free(ctx->object);
+ heap_free(ctx->free);
+}
+
+static void wined3d_view_vk_destroy(struct wined3d_device *device,
+ VkImageView *vk_image_view, uint64_t *command_buffer_id, void *view_vk)
+{
+ struct wined3d_view_vk_destroy_ctx *ctx, c;
+
+ if (!(ctx = heap_alloc(sizeof(*ctx))))
+ ctx = &c;
+ ctx->device_vk = wined3d_device_vk(device);
+ ctx->vk_image_view = vk_image_view;
+ ctx->command_buffer_id = command_buffer_id;
+ ctx->object = view_vk;
+ ctx->free = ctx != &c ? ctx : NULL;
+
+ wined3d_cs_destroy_object(device->cs, wined3d_view_vk_destroy_object, ctx);
+ if (ctx == &c)
+ device->cs->ops->finish(device->cs, WINED3D_CS_QUEUE_DEFAULT);
+}
+
static void adapter_vk_destroy_rendertarget_view(struct wined3d_rendertarget_view *view)
{
struct wined3d_rendertarget_view_vk *view_vk = wined3d_rendertarget_view_vk(view);
@@ -1215,7 +1272,7 @@ static void adapter_vk_destroy_rendertarget_view(struct wined3d_rendertarget_vie
if (swapchain_count)
wined3d_device_incref(device);
wined3d_rendertarget_view_cleanup(&view_vk->v);
- wined3d_cs_destroy_object(device->cs, heap_free, view_vk);
+ wined3d_view_vk_destroy(device, &view_vk->vk_image_view, &view_vk->command_buffer_id, view_vk);
if (swapchain_count)
wined3d_device_decref(device);
}
diff --git a/dlls/wined3d/context_vk.c b/dlls/wined3d/context_vk.c
index 76aafa4c110..f5a321b076c 100644
--- a/dlls/wined3d/context_vk.c
+++ b/dlls/wined3d/context_vk.c
@@ -444,6 +444,31 @@ void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk,
o->command_buffer_id = command_buffer_id;
}
+void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk,
+ VkImageView vk_view, uint64_t command_buffer_id)
+{
+ struct wined3d_device_vk *device_vk = wined3d_device_vk(context_vk->c.device);
+ const struct wined3d_vk_info *vk_info = context_vk->vk_info;
+ struct wined3d_retired_object_vk *o;
+
+ if (context_vk->completed_command_buffer_id > command_buffer_id)
+ {
+ VK_CALL(vkDestroyImageView(device_vk->vk_device, vk_view, NULL));
+ TRACE("Destroyed image view 0x%s.\n", wine_dbgstr_longlong(vk_view));
+ return;
+ }
+
+ if (!(o = wined3d_context_vk_get_retired_object_vk(context_vk)))
+ {
+ ERR("Leaking image view 0x%s.\n", wine_dbgstr_longlong(vk_view));
+ return;
+ }
+
+ o->type = WINED3D_RETIRED_IMAGE_VIEW_VK;
+ o->u.vk_image_view = vk_view;
+ o->command_buffer_id = command_buffer_id;
+}
+
void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk, const struct wined3d_bo_vk *bo)
{
size_t object_size, idx;
@@ -537,6 +562,11 @@ static void wined3d_context_vk_cleanup_resources(struct wined3d_context_vk *cont
TRACE("Destroyed image 0x%s.\n", wine_dbgstr_longlong(o->u.vk_image));
break;
+ case WINED3D_RETIRED_IMAGE_VIEW_VK:
+ VK_CALL(vkDestroyImageView(device_vk->vk_device, o->u.vk_image_view, NULL));
+ TRACE("Destroyed image view 0x%s.\n", wine_dbgstr_longlong(o->u.vk_image_view));
+ break;
+
default:
ERR("Unhandled object type %#x.\n", o->type);
break;
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index 70acc5b1822..0e39ad55a8c 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -4830,7 +4830,7 @@ static BOOL wined3d_texture_vk_load_sysmem(struct wined3d_texture_vk *texture_vk
return TRUE;
}
-static BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
+BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
struct wined3d_context_vk *context_vk)
{
const struct wined3d_format_vk *format_vk;
@@ -4863,7 +4863,7 @@ static BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *textur
create_info.pNext = NULL;
create_info.flags = 0;
- if (wined3d_format_is_typeless(&format_vk->f))
+ if (wined3d_format_is_typeless(&format_vk->f) || texture_vk->t.swapchain)
create_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
switch (resource->type)
diff --git a/dlls/wined3d/view.c b/dlls/wined3d/view.c
index 093143c674f..438d9a8b18f 100644
--- a/dlls/wined3d/view.c
+++ b/dlls/wined3d/view.c
@@ -621,14 +621,140 @@ HRESULT wined3d_rendertarget_view_gl_init(struct wined3d_rendertarget_view_gl *v
return hr;
}
+static VkImageViewType vk_image_view_type_from_wined3d(enum wined3d_resource_type type, uint32_t flags)
+{
+ switch (type)
+ {
+ case WINED3D_RTYPE_TEXTURE_1D:
+ if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
+ return VK_IMAGE_VIEW_TYPE_1D_ARRAY;
+ else
+ return VK_IMAGE_VIEW_TYPE_1D;
+
+ case WINED3D_RTYPE_TEXTURE_2D:
+ if (flags & WINED3D_VIEW_TEXTURE_CUBE)
+ {
+ if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
+ return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
+ else
+ return VK_IMAGE_VIEW_TYPE_CUBE;
+ }
+ if (flags & WINED3D_VIEW_TEXTURE_ARRAY)
+ return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ else
+ return VK_IMAGE_VIEW_TYPE_2D;
+
+ case WINED3D_RTYPE_TEXTURE_3D:
+ return VK_IMAGE_VIEW_TYPE_3D;
+
+ default:
+ ERR("Unhandled resource type %s.\n", debug_d3dresourcetype(type));
+ return ~0u;
+ }
+}
+
+static void wined3d_render_target_view_vk_cs_init(void *object)
+{
+ struct wined3d_rendertarget_view_vk *view_vk = object;
+ struct wined3d_view_desc *desc = &view_vk->v.desc;
+ const struct wined3d_format_vk *format_vk;
+ struct VkImageViewCreateInfo create_info;
+ const struct wined3d_vk_info *vk_info;
+ struct wined3d_texture_vk *texture_vk;
+ struct wined3d_device_vk *device_vk;
+ struct wined3d_resource *resource;
+ struct wined3d_context *context;
+ uint32_t default_flags = 0;
+ VkResult vr;
+
+ resource = view_vk->v.resource;
+ if (resource->type == WINED3D_RTYPE_BUFFER)
+ {
+ FIXME("Buffer views not implemented.\n");
+ return;
+ }
+
+ texture_vk = wined3d_texture_vk(texture_from_resource(resource));
+ format_vk = wined3d_format_vk(view_vk->v.format);
+
+ if (texture_vk->t.layer_count > 1)
+ default_flags |= WINED3D_VIEW_TEXTURE_ARRAY;
+
+ if (resource->format->id == format_vk->f.id && desc->flags == default_flags
+ && !desc->u.texture.level_idx && desc->u.texture.level_count == texture_vk->t.level_count
+ && !desc->u.texture.layer_idx && desc->u.texture.layer_count == texture_vk->t.layer_count
+ && !is_stencil_view_format(&format_vk->f) && resource->type != WINED3D_RTYPE_TEXTURE_3D
+ && is_identity_fixup(format_vk->f.color_fixup))
+ {
+ TRACE("Creating identity render target view.\n");
+ return;
+ }
+
+ if (texture_vk->t.swapchain && texture_vk->t.swapchain->state.desc.backbuffer_count > 1)
+ {
+ FIXME("Swapchain views not supported.\n");
+ return;
+ }
+
+ device_vk = wined3d_device_vk(resource->device);
+ context = context_acquire(&device_vk->d, NULL, 0);
+ vk_info = wined3d_context_vk(context)->vk_info;
+
+ if (!wined3d_texture_vk_prepare_texture(texture_vk, wined3d_context_vk(context)))
+ {
+ ERR("Failed to prepare texture.\n");
+ context_release(context);
+ return;
+ }
+
+ create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ create_info.pNext = NULL;
+ create_info.flags = 0;
+ create_info.image = texture_vk->vk_image;
+ create_info.viewType = vk_image_view_type_from_wined3d(resource->type, desc->flags);
+ if (create_info.viewType == VK_IMAGE_VIEW_TYPE_3D)
+ {
+ if (desc->u.texture.layer_count > 1)
+ create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
+ else
+ create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
+ }
+ create_info.format = format_vk->vk_format;
+ create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
+ create_info.subresourceRange.aspectMask = vk_aspect_mask_from_format(&format_vk->f);
+ create_info.subresourceRange.baseMipLevel = desc->u.texture.level_idx;
+ create_info.subresourceRange.levelCount = desc->u.texture.level_count;
+ create_info.subresourceRange.baseArrayLayer = desc->u.texture.layer_idx;
+ create_info.subresourceRange.layerCount = desc->u.texture.layer_count;
+ if ((vr = VK_CALL(vkCreateImageView(device_vk->vk_device, &create_info, NULL, &view_vk->vk_image_view))) < 0)
+ {
+ ERR("Failed to create Vulkan image view, vr %d.\n", vr);
+ context_release(context);
+ return;
+ }
+ TRACE("Created image view 0x%s.\n", wine_dbgstr_longlong(view_vk->vk_image_view));
+
+ context_release(context);
+}
+
HRESULT wined3d_rendertarget_view_vk_init(struct wined3d_rendertarget_view_vk *view_vk,
const struct wined3d_view_desc *desc, struct wined3d_resource *resource,
void *parent, const struct wined3d_parent_ops *parent_ops)
{
+ HRESULT hr;
+
TRACE("view_vk %p, desc %s, resource %p, parent %p, parent_ops %p.\n",
view_vk, wined3d_debug_view_desc(desc, resource), resource, parent, parent_ops);
- return wined3d_rendertarget_view_init(&view_vk->v, desc, resource, parent, parent_ops);
+ if (FAILED(hr = wined3d_rendertarget_view_init(&view_vk->v, desc, resource, parent, parent_ops)))
+ return hr;
+
+ wined3d_cs_init_object(resource->device->cs, wined3d_render_target_view_vk_cs_init, view_vk);
+
+ return hr;
}
HRESULT CDECL wined3d_rendertarget_view_create(const struct wined3d_view_desc *desc,
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 2faeca4b35d..43bdb26c936 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2228,6 +2228,7 @@ enum wined3d_retired_object_type_vk
WINED3D_RETIRED_BO_SLAB_SLICE_VK,
WINED3D_RETIRED_BUFFER_VK,
WINED3D_RETIRED_IMAGE_VK,
+ WINED3D_RETIRED_IMAGE_VIEW_VK,
};
struct wined3d_retired_object_vk
@@ -2245,6 +2246,7 @@ struct wined3d_retired_object_vk
} slice;
VkBuffer vk_buffer;
VkImage vk_image;
+ VkImageView vk_image_view;
} u;
uint64_t command_buffer_id;
};
@@ -2296,6 +2298,8 @@ void wined3d_context_vk_destroy_bo(struct wined3d_context_vk *context_vk,
const struct wined3d_bo_vk *bo) DECLSPEC_HIDDEN;
void wined3d_context_vk_destroy_image(struct wined3d_context_vk *context_vk,
VkImage vk_image, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
+void wined3d_context_vk_destroy_image_view(struct wined3d_context_vk *context_vk,
+ VkImageView vk_view, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
void wined3d_context_vk_destroy_memory(struct wined3d_context_vk *context_vk,
VkDeviceMemory vk_memory, uint64_t command_buffer_id) DECLSPEC_HIDDEN;
VkCommandBuffer wined3d_context_vk_get_command_buffer(struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
@@ -4002,6 +4006,8 @@ static inline struct wined3d_texture_vk *wined3d_texture_vk(struct wined3d_textu
HRESULT wined3d_texture_vk_init(struct wined3d_texture_vk *texture_vk, struct wined3d_device *device,
const struct wined3d_resource_desc *desc, unsigned int layer_count, unsigned int level_count,
uint32_t flags, void *parent, const struct wined3d_parent_ops *parent_ops) DECLSPEC_HIDDEN;
+BOOL wined3d_texture_vk_prepare_texture(struct wined3d_texture_vk *texture_vk,
+ struct wined3d_context_vk *context_vk) DECLSPEC_HIDDEN;
struct wined3d_renderbuffer_entry
{
@@ -4499,6 +4505,9 @@ HRESULT wined3d_rendertarget_view_gl_init(struct wined3d_rendertarget_view_gl *v
struct wined3d_rendertarget_view_vk
{
struct wined3d_rendertarget_view v;
+
+ VkImageView vk_image_view;
+ uint64_t command_buffer_id;
};
static inline struct wined3d_rendertarget_view_vk *wined3d_rendertarget_view_vk(
--
2.20.1
1
0