Based on !9515 (this MR is a draft until the first part is accepted).
This is most of the logic of partial presentation. D3D11 only.
Remaining parts:
1. Support for multiple rectangles. Requires changes to command stream and swapchain present op (GL, VK, GDI). I have it implemented, but I'm not confident in my implementation, so it must be a separate review. 2. Scroll. Simple grep.app search shows very little use. Neither Firefox nor Chromium use that. Windows Terminal is the most prominent. So this is low priority (though I have it implemented, it's not very difficult). 3. D3D12. I know of no apps that do partial presentation with D3D12. Most of my experience is with D2D & DComp, I barely have experience with D3D11, D3D12 is even more complicated, so I do not plan on implementing it. 4. Other scaling modes (see TODO). I don't think Wine implements them for D3D11. 5. Performance improvement? Right now dirty backbuffer regions are always tracked for correctness. I bet Windows does it better in the most common cases when there is no partial presentation.
-- v2: wined3d: Initial partial present implementation wined3d: Track the dirty regions of the swapchain backbuffers
From: Andrew Boyarshin andrew.boyarshin@gmail.com
--- dlls/dxgi/tests/Makefile.in | 2 +- dlls/dxgi/tests/dxgi.c | 753 ++++++++++++++++++++++++++++++++++++ 2 files changed, 754 insertions(+), 1 deletion(-)
diff --git a/dlls/dxgi/tests/Makefile.in b/dlls/dxgi/tests/Makefile.in index add3803ca40..4e312b27d73 100644 --- a/dlls/dxgi/tests/Makefile.in +++ b/dlls/dxgi/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = dxgi.dll -IMPORTS = d3d10_1 dxgi user32 +IMPORTS = d3d10_1 dxgi gdi32 user32 EXTRADLLFLAGS = -Wl,--subsystem,console:5.2
SOURCES = \ diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index 2e3131a7536..c0d7c4bca79 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -8531,6 +8531,757 @@ static void test_subresource_surface(void) ok(!refcount, "Device has %lu references left.\n", refcount); }
+struct resource_readback +{ + ID3D11Resource *resource; + D3D11_MAPPED_SUBRESOURCE map_desc; + ID3D11DeviceContext *immediate_context; + unsigned int width, height, depth, sub_resource_idx; +}; + +static void init_resource_readback(ID3D11Resource *resource, ID3D11Resource *readback_resource, + unsigned int width, unsigned int height, unsigned int depth, unsigned int sub_resource_idx, + ID3D11Device *device, struct resource_readback *rb) +{ + HRESULT hr; + + rb->resource = readback_resource; + rb->width = width; + rb->height = height; + rb->depth = depth; + rb->sub_resource_idx = sub_resource_idx; + + ID3D11Device_GetImmediateContext(device, &rb->immediate_context); + + ID3D11DeviceContext_CopyResource(rb->immediate_context, rb->resource, resource); + if (FAILED(hr = ID3D11DeviceContext_Map(rb->immediate_context, + rb->resource, sub_resource_idx, D3D11_MAP_READ, 0, &rb->map_desc))) + { + trace("Failed to map resource, hr %#lx.\n", hr); + ID3D11Resource_Release(rb->resource); + rb->resource = NULL; + ID3D11DeviceContext_Release(rb->immediate_context); + rb->immediate_context = NULL; + } +} + +static void get_texture_readback(ID3D11Texture2D *texture, unsigned int sub_resource_idx, + struct resource_readback *rb) +{ + D3D11_TEXTURE2D_DESC texture_desc; + ID3D11Resource *rb_texture; + unsigned int miplevel; + ID3D11Device *device; + HRESULT hr; + + memset(rb, 0, sizeof(*rb)); + + ID3D11Texture2D_GetDevice(texture, &device); + + ID3D11Texture2D_GetDesc(texture, &texture_desc); + texture_desc.Usage = D3D11_USAGE_STAGING; + texture_desc.BindFlags = 0; + texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + texture_desc.MiscFlags = 0; + if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, (ID3D11Texture2D **)&rb_texture))) + { + trace("Failed to create texture, hr %#lx.\n", hr); + ID3D11Device_Release(device); + return; + } + + miplevel = sub_resource_idx % texture_desc.MipLevels; + init_resource_readback((ID3D11Resource *)texture, rb_texture, + max(1, texture_desc.Width >> miplevel), + max(1, texture_desc.Height >> miplevel), + 1, sub_resource_idx, device, rb); + + ID3D11Device_Release(device); +} + +static void *get_readback_data(struct resource_readback *rb, + unsigned int x, unsigned int y, unsigned int z, unsigned byte_width) +{ + return (BYTE *)rb->map_desc.pData + z * rb->map_desc.DepthPitch + y * rb->map_desc.RowPitch + x * byte_width; +} + +static DWORD get_readback_u32(struct resource_readback *rb, unsigned int x, unsigned int y, unsigned int z) +{ + return *(DWORD *)get_readback_data(rb, x, y, z, sizeof(DWORD)); +} + +static DWORD get_readback_color(struct resource_readback *rb, unsigned int x, unsigned int y, unsigned int z) +{ + return get_readback_u32(rb, x, y, z); +} + +static void release_resource_readback(struct resource_readback *rb) +{ + ID3D11DeviceContext_Unmap(rb->immediate_context, rb->resource, rb->sub_resource_idx); + ID3D11Resource_Release(rb->resource); + ID3D11DeviceContext_Release(rb->immediate_context); +} + +static BOOL compare_uint(unsigned int x, unsigned int y, unsigned int max_diff) +{ + unsigned int diff = x > y ? x - y : y - x; + + return diff <= max_diff; +} + +static BOOL compare_color(DWORD c1, DWORD c2, BYTE max_diff) +{ + return compare_uint(c1 & 0xff, c2 & 0xff, max_diff) + && compare_uint((c1 >> 8) & 0xff, (c2 >> 8) & 0xff, max_diff) + && compare_uint((c1 >> 16) & 0xff, (c2 >> 16) & 0xff, max_diff) + && compare_uint((c1 >> 24) & 0xff, (c2 >> 24) & 0xff, max_diff); +} + +#define check_colors(a, b, c, d, e, f, g) check_colors_(__FILE__, __LINE__, a, b, c, d, e, f, g) +static void check_colors_(const char* file, int line, ID3D11Texture2D *texture, unsigned int x, unsigned int y, DWORD expected1, DWORD expected2, DWORD expected3, DWORD expected4) +{ + struct resource_readback rb; + DWORD actual1, actual2, actual3, actual4; + + get_texture_readback(texture, 0, &rb); + actual1 = get_readback_color(&rb, x, y, 0); + actual2 = get_readback_color(&rb, x + 1, y, 0); + actual3 = get_readback_color(&rb, x, y + 1, 0); + actual4 = get_readback_color(&rb, x + 1, y + 1, 0); + release_resource_readback(&rb); + + ok_(file, line)(compare_color(actual1, expected1, 1), "(x=%u, y=%u) expected color = 0x%08lx, actual color = 0x%08lx.\n", x, y, expected1, actual1); + ok_(file, line)(compare_color(actual2, expected2, 1), "(x=%u, y=%u) expected color = 0x%08lx, actual color = 0x%08lx.\n", x + 1, y, expected2, actual2); + ok_(file, line)(compare_color(actual3, expected3, 1), "(x=%u, y=%u) expected color = 0x%08lx, actual color = 0x%08lx.\n", x, y + 1, expected3, actual3); + ok_(file, line)(compare_color(actual4, expected4, 1), "(x=%u, y=%u) expected color = 0x%08lx, actual color = 0x%08lx.\n", x + 1, y + 1, expected4, actual4); +} + +#define check_color(a, b, c, d) check_color_(__FILE__, __LINE__, a, b, c, d) +static void check_color_(const char* file, int line, ID3D11Texture2D *texture, unsigned int x, unsigned int y, DWORD expected) +{ + check_colors_(file, line, texture, x, y, expected, expected, expected, expected); +} + +struct color_rect +{ + RECT rect; + DWORD color; +}; + +#define check_texture(a, b, c, d) check_texture_(__FILE__, __LINE__, a, b, c, d) +static void check_texture_(const char *file, int line, ID3D11Texture2D *texture, DWORD background, + UINT rect_count, struct color_rect *rects) +{ + struct resource_readback rb; + HRGN background_region; + DWORD background_region_data_size; + RGNDATA *background_region_data = NULL; + + get_texture_readback(texture, 0, &rb); + + background_region = CreateRectRgn(0, 0, rb.width, rb.height); + for (UINT i = 0; i < rect_count; ++i) + { + HRGN current_rect_region; + struct color_rect rect = rects[i]; + if (IsRectEmpty(&rect.rect)) + continue; + + current_rect_region = CreateRectRgnIndirect(&rect.rect); + CombineRgn(background_region, background_region, current_rect_region, RGN_DIFF); + DeleteObject(current_rect_region); + for (unsigned int x = rect.rect.left; x < (DWORD)rect.rect.right; ++x) + { + for (unsigned int y = rect.rect.top; y < (DWORD)rect.rect.bottom; ++y) + { + DWORD actual = get_readback_color(&rb, x, y, 0); + DWORD expected = rect.color; + if (!compare_color(actual, expected, 1)) + { + ok_(file, line)(FALSE, "(x=%u, y=%u) rectangle %u expected color = 0x%08lx, actual color = 0x%08lx.\n", i, x, y, expected, actual); + goto skip_rect; + } + } + } + skip_rect:; + } + + background_region_data_size = GetRegionData(background_region, 0, NULL); + background_region_data = (RGNDATA *)malloc(background_region_data_size); + if (!background_region_data) + { + ok_(file, line)(FALSE, "Failed to allocate %lu bytes for background region data\n", background_region_data_size); + goto cleanup; + } + + GetRegionData(background_region, background_region_data_size, background_region_data); + + for (UINT i = 0; i < background_region_data->rdh.nCount; ++i) + { + RECT rect = ((const RECT*)background_region_data->Buffer)[i]; + for (unsigned int x = rect.left; x < (DWORD)rect.right; ++x) + { + for (unsigned int y = rect.top; y < (DWORD)rect.bottom; ++y) + { + DWORD actual = get_readback_color(&rb, x, y, 0); + DWORD expected = background; + if (!compare_color(actual, expected, 1)) + { + ok_(file, line)(FALSE, "(x=%u, y=%u) background expected color = 0x%08lx, actual color = 0x%08lx.\n", x, y, expected, actual); + goto cleanup; + } + } + } + } + + ok_(file, line)(TRUE, "Texture matches\n"); + +cleanup: + free(background_region_data); + DeleteObject(background_region); + release_resource_readback(&rb); +} + +#define check_full(a, b) check_full_(__FILE__, __LINE__, a, b) +static void check_full_(const char *file, int line, ID3D11Texture2D *texture, DWORD expected) +{ + check_texture_(file, line, texture, expected, 0, NULL); +} + +static DWORD RGB_DWORD(BYTE r, BYTE g, BYTE b) +{ + return r | (WORD)g << 8 | (DWORD)b << 16 | 0x80000000u; +} + +struct test_partial_present_common_parameters +{ + DXGI_SWAP_EFFECT swap_effect; + DXGI_SCALING scaling; + UINT buffer_count; + UINT swapchain_width; + UINT swapchain_height; + UINT window_width; + UINT window_height; +}; + +static BOOL prepare_partial_present(struct test_partial_present_common_parameters *parameters, + ID3D11Device **device, + HWND *window, + IDXGISwapChain1 **swapchain, + ID3D11DeviceContext **context) +{ + static const D3D_FEATURE_LEVEL feature_level[] = + { + D3D_FEATURE_LEVEL_11_0, + }; + unsigned int feature_level_count = ARRAY_SIZE(feature_level); + DXGI_SWAP_CHAIN_DESC1 dxgi_desc; + IDXGIDevice *dxgi_device; + IDXGIAdapter *adapter; + IDXGIFactory2 *factory; + RECT rect; + HRESULT hr; + + if (!pD3D11CreateDevice) + { + win_skip("No D3D11 support, skipping partial presentation tests.\n"); + return FALSE; + } + + hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, feature_level, feature_level_count, + D3D11_SDK_VERSION, device, NULL, NULL); + if (FAILED(hr)) + hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_WARP, NULL, 0, feature_level, feature_level_count, + D3D11_SDK_VERSION, device, NULL, NULL); + if (FAILED(hr)) + hr = pD3D11CreateDevice(NULL, D3D_DRIVER_TYPE_REFERENCE, NULL, 0, feature_level, feature_level_count, + D3D11_SDK_VERSION, device, NULL, NULL); + + if (FAILED(hr) || !*device) + { + skip("Failed to create D3D11 device, skipping partial presentation tests.\n"); + return FALSE; + } + + hr = ID3D11Device_QueryInterface(*device, &IID_IDXGIDevice, (void **)&dxgi_device); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDXGIDevice_GetAdapter(dxgi_device, &adapter); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + IDXGIDevice_Release(dxgi_device); + hr = IDXGIAdapter_GetParent(adapter, &IID_IDXGIFactory2, (void **)&factory); + ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Got unexpected hr %#lx.\n", hr); + IDXGIAdapter_Release(adapter); + if (!factory) + { + win_skip("No IDXGIFactory2, skipping partial presentation tests.\n"); + return FALSE; + } + + SetRect(&rect, 0, 0, parameters->window_width, parameters->window_height); + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW | WS_VISIBLE, FALSE); + *window = CreateWindowA("static", "dxgi_test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, + 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, NULL, NULL); + + dxgi_desc.Width = parameters->swapchain_width; + dxgi_desc.Height = parameters->swapchain_height; + dxgi_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + dxgi_desc.Stereo = FALSE; + dxgi_desc.SampleDesc.Count = 1; + dxgi_desc.SampleDesc.Quality = 0; + dxgi_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + dxgi_desc.BufferCount = parameters->buffer_count; + dxgi_desc.Scaling = parameters->scaling; + dxgi_desc.SwapEffect = parameters->swap_effect; + dxgi_desc.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED; + dxgi_desc.Flags = 0; + + hr = IDXGIFactory2_CreateSwapChainForHwnd(factory, (IUnknown *)*device, *window, &dxgi_desc, NULL, NULL, swapchain); + ok(hr == S_OK, "Failed to create swapchain, hr %#lx.\n", hr); + IDXGIFactory2_Release(factory); + + ID3D11Device_GetImmediateContext(*device, context); + return TRUE; +} + +struct test_partial_present_grid_backbuffer_info +{ + DWORD background; + struct color_rect rectangles[1]; +}; + +struct test_partial_present_grid_parameters +{ + struct test_partial_present_common_parameters c; + UINT cell_size; + UINT rows; + UINT columns; +}; + +static void test_partial_present_grid_impl(struct test_partial_present_grid_parameters *parameters) +{ + ID3D11Texture2D *backbuffer_0, *backbuffer_last; + ID3D11RenderTargetView *backbuffer_0_rtv; + ID3D11DeviceContext *context; + IDXGISwapChain1 *swapchain; + ID3D11Device *device; + ULONG refcount; + HWND window; + HRESULT hr; + DXGI_PRESENT_PARAMETERS present_params; + RECT dirty_rect; + const UINT buffer_count = parameters->c.buffer_count; + const UINT cell_size = parameters->cell_size; + const UINT rows = parameters->rows; + const UINT columns = parameters->columns; + ID3D11Texture2D **backbuffers = calloc(buffer_count, sizeof(ID3D11Texture2D*)); + const UINT backbuffer_info_size = FIELD_OFFSET(struct test_partial_present_grid_backbuffer_info, rectangles[buffer_count]); + char *backbuffer_info_memory = calloc(buffer_count, backbuffer_info_size); + struct test_partial_present_grid_backbuffer_info **backbuffer_info = calloc(buffer_count + 1, sizeof(*backbuffer_info)); + const DWORD background_dword = RGB_DWORD(1, 1, 1); + const FLOAT background_float[] = { 1.0f / 255, 1.0f / 255, 1.0f / 255, 0.5f }; + +#define PALETTE_SIZE 11 + + const BYTE PALETTE[PALETTE_SIZE][3] = { + {47, 45, 48}, + {90, 71, 67}, + {111, 108, 112}, + {43, 46, 67}, + {75, 109, 65}, + {119, 32, 46}, + {181, 186, 182}, + {207, 187, 123}, + {213, 98, 49}, + {0, 116, 168}, + {51, 190, 204} + }; + + DWORD PALETTE_RGBA_DWORD[PALETTE_SIZE]; + + FLOAT PALETTE_RGBA_FLOAT[PALETTE_SIZE][4]; + + for (UINT i = 0; i < PALETTE_SIZE; ++i) + { + BYTE red = PALETTE[i][0]; + BYTE green = PALETTE[i][1]; + BYTE blue = PALETTE[i][2]; + PALETTE_RGBA_DWORD[i] = RGB_DWORD(red, green, blue); + PALETTE_RGBA_FLOAT[i][0] = red * 1.0f / 255; + PALETTE_RGBA_FLOAT[i][1] = green * 1.0f / 255; + PALETTE_RGBA_FLOAT[i][2] = blue * 1.0f / 255; + PALETTE_RGBA_FLOAT[i][3] = 0.5f; + } + + for (size_t i = 0; i < buffer_count; ++i) + backbuffer_info[i] = (struct test_partial_present_grid_backbuffer_info*)(backbuffer_info_memory + i * backbuffer_info_size); + + if (!prepare_partial_present(¶meters->c, &device, &window, &swapchain, &context)) + return; + + for (UINT i = 0; i < buffer_count; ++i) + { + hr = IDXGISwapChain1_GetBuffer(swapchain, i, &IID_ID3D11Texture2D, (void **)&backbuffers[i]); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + } + + backbuffer_0 = backbuffers[0]; + backbuffer_last = backbuffers[buffer_count - 1]; + + hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_0, NULL, &backbuffer_0_rtv); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + for (UINT i = 0; i < buffer_count; ++i) + check_full(backbuffers[i], 0); + + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, background_float); + + check_full(backbuffer_0, background_dword); + for (UINT i = 1; i < buffer_count; ++i) + check_full(backbuffers[i], 0); + + present_params.DirtyRectsCount = 0; + present_params.pDirtyRects = NULL; + present_params.pScrollOffset = NULL; + present_params.pScrollRect = NULL; + + IDXGISwapChain1_Present1(swapchain, 0, 0, &present_params); + + for (UINT i = 0; i < buffer_count - 1; ++i) + check_full(backbuffers[i], 0); + check_full(backbuffer_last, background_dword); + + present_params.DirtyRectsCount = 1; + present_params.pDirtyRects = &dirty_rect; + + backbuffer_info[buffer_count - 1]->background = background_dword; + + for (UINT row = 0; row < rows; ++row) + { + for (UINT col = 0; col < columns; ++col) + { + const UINT current_index = row * columns + col; + const UINT palette_index = (row * columns + col) % PALETTE_SIZE; + const FLOAT* color_float = PALETTE_RGBA_FLOAT[palette_index]; + const DWORD color_dword = PALETTE_RGBA_DWORD[palette_index]; + + for (UINT k = 0; k < buffer_count; ++k) + flaky_wine check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles); + + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, color_float); + + dirty_rect.top = row * cell_size; + dirty_rect.bottom = (row + 1) * cell_size; + dirty_rect.left = col * cell_size; + dirty_rect.right = (col + 1) * cell_size; + backbuffer_info[0]->background = current_index + 1 >= buffer_count ? color_dword : background_dword; + for (UINT k = 0; k < buffer_count - 1; ++k) + backbuffer_info[0]->rectangles[k] = backbuffer_info[buffer_count - 1]->rectangles[k + 1]; + backbuffer_info[0]->rectangles[buffer_count - 1].color = color_dword; + backbuffer_info[0]->rectangles[buffer_count - 1].rect = dirty_rect; + + IDXGISwapChain1_Present1(swapchain, 0, 0, &present_params); + + backbuffer_info[buffer_count] = backbuffer_info[0]; + for (UINT k = 0; k < buffer_count; ++k) + backbuffer_info[k] = backbuffer_info[k + 1]; + + for (UINT k = 0; k < buffer_count; ++k) + flaky_wine check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles); + } + } + +#undef PALETTE_SIZE + + ID3D11RenderTargetView_Release(backbuffer_0_rtv); + for (UINT i = 0; i < buffer_count; ++i) + ID3D11Texture2D_Release(backbuffers[i]); + IDXGISwapChain1_Release(swapchain); + ID3D11DeviceContext_Release(context); + refcount = ID3D11Device_Release(device); + ok(!refcount, "Device has %lu references left.\n", refcount); + DestroyWindow(window); + free(backbuffer_info); + free(backbuffer_info_memory); + free(backbuffers); +} + +static void test_partial_present_grid(void) +{ + struct test_partial_present_grid_parameters parameters = { + .c.swap_effect = DXGI_SWAP_EFFECT_SEQUENTIAL, .c.buffer_count = 5, + .c.swapchain_width = 640, .c.swapchain_height = 480, + .c.window_width = 640, .c.window_height = 480, + .cell_size = 160, .rows = 3, .columns = 4, + }; + test_partial_present_grid_impl(¶meters); + parameters.c.swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + parameters.c.window_width = 1280; + test_partial_present_grid_impl(¶meters); +} + +static void test_partial_present_scroll_impl(struct test_partial_present_common_parameters *parameters) +{ + ID3D11Texture2D *backbuffer_0, *backbuffer_1, *backbuffer_2; + ID3D11RenderTargetView *backbuffer_0_rtv; + ID3D11DeviceContext *context; + IDXGISwapChain1 *swapchain; + ID3D11Device *device; + ULONG refcount; + HWND window; + HRESULT hr; + DXGI_PRESENT_PARAMETERS present_params; + + static const float red[] = {1.0f, 0.0f, 0.0f, 0.5f}; + static const float green[] = {0.0f, 1.0f, 0.0f, 0.5f}; + static const float blue[] = {0.0f, 0.0f, 1.0f, 0.5f}; + + const DWORD RED = RGB_DWORD(0xFF, 0, 0); + const DWORD GREEN = RGB_DWORD(0, 0xFF, 0); + const DWORD BLUE = RGB_DWORD(0, 0, 0xFF); + const DWORD BLACK = 0x00000000; + + RECT dirty_rects_green[] = { + {.left = 50, .top = 50, .right = 100, .bottom = 100}, + {.left = 200, .top = 80, .right = 400, .bottom = 300} + }; + + RECT dirty_rects_blue[] = { + {.left = 50, .top = 40, .right = 100, .bottom = 80}, + {.left = 10, .top = 400, .right = 600, .bottom = 420} + }; + + RECT scroll_rect = {.left = 10, .top = 10, .right = 600, .bottom = 400}; + POINT scroll_offset = {.x = 0, .y = -20}; + + if (!prepare_partial_present(parameters, &device, &window, &swapchain, &context)) + return; + + hr = IDXGISwapChain1_GetBuffer(swapchain, 0, &IID_ID3D11Texture2D, (void **)&backbuffer_0); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDXGISwapChain1_GetBuffer(swapchain, 1, &IID_ID3D11Texture2D, (void **)&backbuffer_1); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + hr = IDXGISwapChain1_GetBuffer(swapchain, 2, &IID_ID3D11Texture2D, (void **)&backbuffer_2); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)backbuffer_0, NULL, &backbuffer_0_rtv); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_full(backbuffer_0, BLACK); + check_full(backbuffer_1, BLACK); + check_full(backbuffer_2, BLACK); + + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, red); + + check_full(backbuffer_0, RED); + check_full(backbuffer_1, BLACK); + check_full(backbuffer_2, BLACK); + + present_params.DirtyRectsCount = 0; + present_params.pDirtyRects = NULL; + present_params.pScrollOffset = NULL; + present_params.pScrollRect = NULL; + + hr = IDXGISwapChain1_Present1(swapchain, 0, 0, &present_params); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_full(backbuffer_0, BLACK); + check_full(backbuffer_1, BLACK); + check_full(backbuffer_2, RED); + + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, green); + + check_full(backbuffer_0, GREEN); + check_full(backbuffer_1, BLACK); + check_full(backbuffer_2, RED); + + present_params.DirtyRectsCount = ARRAYSIZE(dirty_rects_green); + present_params.pDirtyRects = dirty_rects_green; + present_params.pScrollOffset = NULL; + present_params.pScrollRect = NULL; + + hr = IDXGISwapChain1_Present1(swapchain, 0, 0, &present_params); + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_full(backbuffer_0, BLACK); + check_full(backbuffer_1, RED); + + todo_wine check_color(backbuffer_2, 5, 5, RED); + todo_wine check_color(backbuffer_2, 20, 20, RED); + todo_wine check_color(backbuffer_2, 49, 29, RED); + todo_wine check_color(backbuffer_2, 49, 39, RED); + flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + todo_wine check_color(backbuffer_2, 99, 29, RED); + todo_wine check_color(backbuffer_2, 99, 39, RED); + flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 199, 59, RED); + todo_wine check_color(backbuffer_2, 399, 59, RED); + flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 9, 399, RED); + todo_wine check_color(backbuffer_2, 9, 419, RED); + todo_wine check_color(backbuffer_2, 599, 399, RED); + todo_wine check_color(backbuffer_2, 599, 419, RED); + + ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, blue); + + check_full(backbuffer_0, BLUE); + check_full(backbuffer_1, RED); + + todo_wine check_color(backbuffer_2, 5, 5, RED); + todo_wine check_color(backbuffer_2, 20, 20, RED); + todo_wine check_color(backbuffer_2, 49, 29, RED); + todo_wine check_color(backbuffer_2, 49, 39, RED); + flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + todo_wine check_color(backbuffer_2, 99, 29, RED); + todo_wine check_color(backbuffer_2, 99, 39, RED); + flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 199, 59, RED); + todo_wine check_color(backbuffer_2, 399, 59, RED); + flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 9, 399, RED); + todo_wine check_color(backbuffer_2, 9, 419, RED); + todo_wine check_color(backbuffer_2, 599, 399, RED); + todo_wine check_color(backbuffer_2, 599, 419, RED); + + present_params.DirtyRectsCount = ARRAYSIZE(dirty_rects_blue); + present_params.pDirtyRects = dirty_rects_blue; + present_params.pScrollRect = &scroll_rect; + present_params.pScrollOffset = &scroll_offset; + + hr = IDXGISwapChain1_Present1(swapchain, 0, 0, &present_params); + + if (is_flip_model(parameters->swap_effect)) + { + ok(hr == S_OK, "Got unexpected hr %#lx.\n", hr); + + check_full(backbuffer_0, RED); + + todo_wine check_color(backbuffer_1, 5, 5, RED); + todo_wine check_color(backbuffer_1, 20, 20, RED); + todo_wine check_color(backbuffer_1, 49, 29, RED); + todo_wine check_color(backbuffer_1, 49, 39, RED); + flaky_wine check_colors(backbuffer_1, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_1, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_1, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + todo_wine check_color(backbuffer_1, 99, 29, RED); + todo_wine check_color(backbuffer_1, 99, 39, RED); + flaky_wine check_colors(backbuffer_1, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_1, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_1, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_1, 199, 59, RED); + todo_wine check_color(backbuffer_1, 399, 59, RED); + flaky_wine check_colors(backbuffer_1, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_1, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_1, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_1, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_1, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_1, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_1, 9, 399, RED); + todo_wine check_color(backbuffer_1, 9, 419, RED); + todo_wine check_color(backbuffer_1, 599, 399, RED); + todo_wine check_color(backbuffer_1, 599, 419, RED); + + todo_wine check_color(backbuffer_2, 5, 5, RED); + todo_wine check_color(backbuffer_2, 20, 20, RED); + flaky_wine check_colors(backbuffer_2, 49, 29, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 49, 39, RED, GREEN, RED, BLUE); /* left side, green-blue edge */ + flaky_wine check_colors(backbuffer_2, 49, 49, RED, BLUE, RED, BLUE); /* left side */ + flaky_wine check_colors(backbuffer_2, 49, 79, RED, BLUE, RED, RED); /* bottom-left corner */ + todo_wine check_color(backbuffer_2, 49, 99, RED); + flaky_wine check_colors(backbuffer_2, 99, 29, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 99, 39, GREEN, RED, BLUE, RED); /* right side, green-blue edge */ + flaky_wine check_colors(backbuffer_2, 99, 49, BLUE, RED, BLUE, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 99, 79, BLUE, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 99, 99, RED); + flaky_wine check_colors(backbuffer_2, 199, 59, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 59, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 199, 79, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 399, 79, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 199, 299, RED); + todo_wine check_color(backbuffer_2, 399, 299, RED); + flaky_wine check_colors(backbuffer_2, 9, 399, RED, RED, RED, BLUE); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 9, 419, RED, BLUE, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_2, 599, 399, RED, RED, BLUE, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 599, 419, BLUE, RED, RED, RED); /* bottom-right corner */ + } + else + { + todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + + /* No changes. */ + + todo_wine check_full(backbuffer_0, BLUE); + todo_wine check_full(backbuffer_1, RED); + + todo_wine check_color(backbuffer_2, 5, 5, RED); + todo_wine check_color(backbuffer_2, 20, 20, RED); + todo_wine check_color(backbuffer_2, 49, 29, RED); + todo_wine check_color(backbuffer_2, 49, 39, RED); + flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + todo_wine check_color(backbuffer_2, 99, 29, RED); + todo_wine check_color(backbuffer_2, 99, 39, RED); + flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 199, 59, RED); + todo_wine check_color(backbuffer_2, 399, 59, RED); + flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + todo_wine check_color(backbuffer_2, 9, 399, RED); + todo_wine check_color(backbuffer_2, 9, 419, RED); + todo_wine check_color(backbuffer_2, 599, 399, RED); + todo_wine check_color(backbuffer_2, 599, 419, RED); + } + + ID3D11RenderTargetView_Release(backbuffer_0_rtv); + ID3D11Texture2D_Release(backbuffer_0); + ID3D11Texture2D_Release(backbuffer_1); + ID3D11Texture2D_Release(backbuffer_2); + IDXGISwapChain1_Release(swapchain); + ID3D11DeviceContext_Release(context); + refcount = ID3D11Device_Release(device); + ok(!refcount, "Device has %lu references left.\n", refcount); + DestroyWindow(window); +} + +static void test_partial_present_scroll(void) +{ + struct test_partial_present_common_parameters parameters = { + .swap_effect = DXGI_SWAP_EFFECT_SEQUENTIAL, .buffer_count = 3, + .swapchain_width = 640, .swapchain_height = 480, + .window_width = 640, .window_height = 480, + }; + test_partial_present_scroll_impl(¶meters); + parameters.swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; + parameters.window_width = 1280; + test_partial_present_scroll_impl(¶meters); +} + START_TEST(dxgi) { HMODULE dxgi_module, d3d11_module, d3d12_module, gdi32_module; @@ -8590,6 +9341,8 @@ START_TEST(dxgi) queue_test(test_object_wrapping); queue_test(test_factory_check_feature_support); queue_test(test_video_memory_budget_notification); + queue_test(test_partial_present_grid); + queue_test(test_partial_present_scroll);
run_queued_tests();
From: Andrew Boyarshin andrew.boyarshin@gmail.com
--- dlls/dxgi/swapchain.c | 50 ++++++++++++++++++++++++++++++++++++------ dlls/dxgi/tests/dxgi.c | 6 ++--- 2 files changed, 46 insertions(+), 10 deletions(-)
diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index 5c49c7f2482..fd790cc7fe2 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -60,6 +60,18 @@ static BOOL dxgi_validate_flip_swap_effect_format(DXGI_FORMAT format) } }
+static BOOL dxgi_has_scroll_present_parameters(const DXGI_PRESENT_PARAMETERS *present_parameters) +{ + if (present_parameters->pScrollOffset && present_parameters->pScrollRect) + { + POINT scroll_offset = *present_parameters->pScrollOffset; + + return (scroll_offset.x || scroll_offset.y) && !IsRectEmpty(present_parameters->pScrollRect); + } + + return FALSE; +} + BOOL dxgi_validate_swapchain_desc(const DXGI_SWAP_CHAIN_DESC1 *desc) { unsigned int min_buffer_count; @@ -302,7 +314,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetDevice(IDXGISwapChain4 *ifac /* IDXGISwapChain1 methods */
static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, - unsigned int sync_interval, unsigned int flags) + unsigned int sync_interval, unsigned int flags, const DXGI_PRESENT_PARAMETERS *dxgi_parameters) { HRESULT hr;
@@ -323,6 +335,27 @@ static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, return S_OK; }
+ if (dxgi_parameters && dxgi_parameters->DirtyRectsCount && dxgi_parameters->pDirtyRects) + { + FIXME("Ignored %u present dirty rectangles at %p ([0] = %s).\n", dxgi_parameters->DirtyRectsCount, dxgi_parameters->pDirtyRects, wine_dbgstr_rect(&dxgi_parameters->pDirtyRects[0])); + } + + if (dxgi_parameters && dxgi_has_scroll_present_parameters(dxgi_parameters)) + { + struct wined3d_swapchain_desc swapchain_desc; + enum wined3d_swap_effect swap_effect; + wined3d_swapchain_get_desc(swapchain->wined3d_swapchain, &swapchain_desc); + swap_effect = swapchain_desc.swap_effect; + if (swap_effect != WINED3D_SWAP_EFFECT_FLIP_SEQUENTIAL && swap_effect != WINED3D_SWAP_EFFECT_FLIP_DISCARD) + { + WARN("Partial presentation scroll (%s + %s) is only allowed on Flip-model swapchains.\n", + wine_dbgstr_rect(dxgi_parameters->pScrollRect), wine_dbgstr_point(dxgi_parameters->pScrollOffset)); + return DXGI_ERROR_INVALID_CALL; + } + + FIXME("Ignored present %s scroll of %s rectangle.\n", wine_dbgstr_point(dxgi_parameters->pScrollOffset), wine_dbgstr_rect(dxgi_parameters->pScrollRect)); + } + if (SUCCEEDED(hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, NULL, NULL, NULL, sync_interval, 0))) InterlockedIncrement(&swapchain->present_count); return hr; @@ -334,7 +367,7 @@ static HRESULT STDMETHODCALLTYPE DECLSPEC_HOTPATCH d3d11_swapchain_Present(IDXGI
TRACE("iface %p, sync_interval %u, flags %#x.\n", iface, sync_interval, flags);
- return d3d11_swapchain_present(swapchain, sync_interval, flags); + return d3d11_swapchain_present(swapchain, sync_interval, flags, NULL); }
static HRESULT STDMETHODCALLTYPE d3d11_swapchain_GetBuffer(IDXGISwapChain4 *iface, @@ -708,10 +741,7 @@ static HRESULT STDMETHODCALLTYPE d3d11_swapchain_Present1(IDXGISwapChain4 *iface TRACE("iface %p, sync_interval %u, flags %#x, present_parameters %p.\n", iface, sync_interval, flags, present_parameters);
- if (present_parameters) - FIXME("Ignored present parameters %p.\n", present_parameters); - - return d3d11_swapchain_present(swapchain, sync_interval, flags); + return d3d11_swapchain_present(swapchain, sync_interval, flags, present_parameters); }
static BOOL STDMETHODCALLTYPE d3d11_swapchain_IsTemporaryMonoSupported(IDXGISwapChain4 *iface) @@ -2783,7 +2813,13 @@ static HRESULT STDMETHODCALLTYPE d3d12_swapchain_Present1(IDXGISwapChain4 *iface iface, sync_interval, flags, present_parameters);
if (present_parameters) - FIXME("Ignored present parameters %p.\n", present_parameters); + { + if (present_parameters->DirtyRectsCount && present_parameters->pDirtyRects) + FIXME("Ignored %u present dirty rectangles at %p ([0] = %s).\n", present_parameters->DirtyRectsCount, present_parameters->pDirtyRects, wine_dbgstr_rect(&present_parameters->pDirtyRects[0])); + + if (dxgi_has_scroll_present_parameters(present_parameters)) + FIXME("Ignored present %s scroll of %s rectangle.\n", wine_dbgstr_point(present_parameters->pScrollOffset), wine_dbgstr_rect(present_parameters->pScrollRect)); + }
return d3d12_swapchain_present(swapchain, sync_interval, flags); } diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index c0d7c4bca79..812695c2f99 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -9225,12 +9225,12 @@ static void test_partial_present_scroll_impl(struct test_partial_present_common_ } else { - todo_wine ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr); + ok(hr == DXGI_ERROR_INVALID_CALL, "Got unexpected hr %#lx.\n", hr);
/* No changes. */
- todo_wine check_full(backbuffer_0, BLUE); - todo_wine check_full(backbuffer_1, RED); + check_full(backbuffer_0, BLUE); + check_full(backbuffer_1, RED);
todo_wine check_color(backbuffer_2, 5, 5, RED); todo_wine check_color(backbuffer_2, 20, 20, RED);
From: Andrew Boyarshin andrew.boyarshin@gmail.com
--- dlls/wined3d/context_gl.c | 2 +- dlls/wined3d/cs.c | 6 +-- dlls/wined3d/device.c | 8 ++-- dlls/wined3d/surface.c | 2 +- dlls/wined3d/swapchain.c | 81 ++++++++++++++++++++++------------ dlls/wined3d/texture.c | 2 +- dlls/wined3d/wined3d_private.h | 8 +++- 7 files changed, 70 insertions(+), 39 deletions(-)
diff --git a/dlls/wined3d/context_gl.c b/dlls/wined3d/context_gl.c index ac1b9370fc1..6d16bc69b4e 100644 --- a/dlls/wined3d/context_gl.c +++ b/dlls/wined3d/context_gl.c @@ -4340,7 +4340,7 @@ struct wined3d_context *wined3d_context_gl_acquire(const struct wined3d_device * struct wined3d_swapchain *swapchain = device->swapchains[0];
if (swapchain->back_buffers) - texture = swapchain->back_buffers[0]; + texture = swapchain->back_buffers[0].texture; else texture = swapchain->front_buffer; sub_resource_idx = 0; diff --git a/dlls/wined3d/cs.c b/dlls/wined3d/cs.c index 21ed1264971..de969ba82fd 100644 --- a/dlls/wined3d/cs.c +++ b/dlls/wined3d/cs.c @@ -671,7 +671,7 @@ static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data)
swapchain = op->swapchain; desc = &swapchain->state.desc; - back_buffer = swapchain->back_buffers[0]; + back_buffer = swapchain->back_buffers[0].texture; wined3d_swapchain_set_window(swapchain, op->dst_window_override);
if ((logo_texture = swapchain->device->logo_texture)) @@ -711,7 +711,7 @@ static void wined3d_cs_exec_present(struct wined3d_cs *cs, const void *data) swapchain->swapchain_ops->swapchain_present(swapchain, &op->src_rect, &op->dst_rect, op->swap_interval, op->flags);
/* Discard buffers if the swap effect allows it. */ - back_buffer = swapchain->back_buffers[desc->backbuffer_count - 1]; + back_buffer = swapchain->back_buffers[desc->backbuffer_count - 1].texture; if (desc->swap_effect == WINED3D_SWAP_EFFECT_DISCARD || desc->swap_effect == WINED3D_SWAP_EFFECT_FLIP_DISCARD) wined3d_texture_validate_location(back_buffer, 0, WINED3D_LOCATION_DISCARDED);
@@ -777,7 +777,7 @@ void wined3d_cs_emit_present(struct wined3d_cs *cs, struct wined3d_swapchain *sw wined3d_resource_reference(&swapchain->front_buffer->resource); for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i) { - wined3d_resource_reference(&swapchain->back_buffers[i]->resource); + wined3d_resource_reference(&swapchain->back_buffers[i].texture->resource); }
wined3d_device_context_submit(&cs->c, WINED3D_CS_QUEUE_DEFAULT); diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 443bf10ab76..eb26ffe8d4e 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1487,7 +1487,7 @@ void wined3d_device_gl_create_primary_opengl_context_cs(void *object)
device = &device_gl->d; swapchain = device->swapchains[0]; - target = swapchain->back_buffers ? swapchain->back_buffers[0] : swapchain->front_buffer; + target = swapchain->back_buffers ? swapchain->back_buffers[0].texture : swapchain->front_buffer; if (!(context = context_acquire(device, target, 0))) { WARN("Failed to acquire context.\n"); @@ -1571,7 +1571,7 @@ HRESULT wined3d_device_set_implicit_swapchain(struct wined3d_device *device, str swapchain_desc = &swapchain->state.desc; if (swapchain_desc->backbuffer_count && swapchain_desc->backbuffer_bind_flags & WINED3D_BIND_RENDER_TARGET) { - struct wined3d_resource *back_buffer = &swapchain->back_buffers[0]->resource; + struct wined3d_resource *back_buffer = &swapchain->back_buffers[0].texture->resource; struct wined3d_view_desc view_desc;
view_desc.format_id = back_buffer->format->id; @@ -5154,7 +5154,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, update_swapchain_flags(swapchain->front_buffer); for (i = 0; i < current_desc->backbuffer_count; ++i) { - update_swapchain_flags(swapchain->back_buffers[i]); + update_swapchain_flags(swapchain->back_buffers[i].texture); } }
@@ -5212,7 +5212,7 @@ HRESULT CDECL wined3d_device_reset(struct wined3d_device *device, } if (current_desc->backbuffer_count && current_desc->backbuffer_bind_flags & WINED3D_BIND_RENDER_TARGET) { - struct wined3d_resource *back_buffer = &swapchain->back_buffers[0]->resource; + struct wined3d_resource *back_buffer = &swapchain->back_buffers[0].texture->resource;
view_desc.format_id = back_buffer->format->id; view_desc.flags = 0; diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 067b3afc30e..7f519cb553e 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1586,7 +1586,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ } else if (dst_swapchain && dst_swapchain->back_buffers && dst_texture == dst_swapchain->front_buffer - && src_texture == dst_swapchain->back_buffers[0]) + && src_texture == dst_swapchain->back_buffers[0].texture) { /* Use present for back -> front blits. The idea behind this is that * present is potentially faster than a blit, in particular when FBO diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index a1000ec2393..9156d74beef 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -53,9 +53,11 @@ void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain)
while (i--) { - wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); - if (wined3d_texture_decref(swapchain->back_buffers[i])) - WARN("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]); + struct wined3d_backbuffer *backbuffer = &swapchain->back_buffers[i]; + if (backbuffer->dirty_region) DeleteObject(backbuffer->dirty_region); + wined3d_texture_set_swapchain(backbuffer->texture, NULL); + if (wined3d_texture_decref(backbuffer->texture)) + WARN("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i].texture); } free(swapchain->back_buffers); swapchain->back_buffers = NULL; @@ -272,9 +274,9 @@ struct wined3d_texture * CDECL wined3d_swapchain_get_back_buffer(const struct wi return NULL; }
- TRACE("Returning back buffer %p.\n", swapchain->back_buffers[back_buffer_idx]); + TRACE("Returning back buffer %p.\n", swapchain->back_buffers[back_buffer_idx].texture);
- return swapchain->back_buffers[back_buffer_idx]; + return swapchain->back_buffers[back_buffer_idx].texture; }
struct wined3d_texture * CDECL wined3d_swapchain_get_front_buffer(const struct wined3d_swapchain *swapchain) @@ -399,7 +401,7 @@ HRESULT CDECL wined3d_swapchain_get_gamma_ramp(const struct wined3d_swapchain *s static void swapchain_blit_gdi(struct wined3d_swapchain *swapchain, struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect) { - struct wined3d_texture *back_buffer = swapchain->back_buffers[0]; + struct wined3d_texture *back_buffer = swapchain->back_buffers[0].texture; D3DKMT_DESTROYDCFROMMEMORY destroy_desc; D3DKMT_CREATEDCFROMMEMORY create_desc; const struct wined3d_format *format; @@ -466,7 +468,7 @@ static void swapchain_blit_gdi(struct wined3d_swapchain *swapchain, static void swapchain_blit(const struct wined3d_swapchain *swapchain, struct wined3d_context *context, const RECT *src_rect, const RECT *dst_rect) { - struct wined3d_texture *texture = swapchain->back_buffers[0]; + struct wined3d_texture *texture = swapchain->back_buffers[0].texture; struct wined3d_device *device = swapchain->device; enum wined3d_texture_filter_type filter; DWORD location; @@ -516,8 +518,10 @@ static void swapchain_gl_set_swap_interval(struct wined3d_swapchain *swapchain, static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context *context) { struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_backbuffer *backbuffer, *backbuffer_prev; struct wined3d_texture_gl *texture, *texture_prev; struct gl_texture tex0; + HRGN dirty_region0; GLuint rb0; DWORD locations0; unsigned int i; @@ -526,30 +530,36 @@ static void wined3d_swapchain_gl_rotate(struct wined3d_swapchain *swapchain, str if (swapchain->state.desc.backbuffer_count < 2) return;
- texture_prev = wined3d_texture_gl(swapchain->back_buffers[0]); + backbuffer_prev = &swapchain->back_buffers[0]; + texture_prev = wined3d_texture_gl(backbuffer_prev->texture);
/* Back buffer 0 is already in the draw binding. */ + dirty_region0 = backbuffer_prev->dirty_region; tex0 = texture_prev->texture_rgb; rb0 = texture_prev->rb_multisample; locations0 = texture_prev->t.sub_resources[0].locations;
for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i) { - texture = wined3d_texture_gl(swapchain->back_buffers[i]); + backbuffer = &swapchain->back_buffers[i]; + texture = wined3d_texture_gl(backbuffer->texture); sub_resource = &texture->t.sub_resources[0];
if (!(sub_resource->locations & supported_locations)) wined3d_texture_load_location(&texture->t, 0, context, texture->t.resource.draw_binding);
+ backbuffer_prev->dirty_region = backbuffer->dirty_region; texture_prev->texture_rgb = texture->texture_rgb; texture_prev->rb_multisample = texture->rb_multisample;
wined3d_texture_validate_location(&texture_prev->t, 0, sub_resource->locations & supported_locations); wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(sub_resource->locations & supported_locations));
+ backbuffer_prev = backbuffer; texture_prev = texture; }
+ backbuffer_prev->dirty_region = dirty_region0; texture_prev->texture_rgb = tex0; texture_prev->rb_multisample = rb0;
@@ -583,7 +593,7 @@ static bool swapchain_present_is_partial_copy(struct wined3d_swapchain *swapchai static void swapchain_gl_present(struct wined3d_swapchain *swapchain, const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval, uint32_t flags) { - struct wined3d_texture *back_buffer = swapchain->back_buffers[0]; + struct wined3d_texture *back_buffer = swapchain->back_buffers[0].texture; const struct wined3d_pixel_format *pixel_format; const struct wined3d_gl_info *gl_info; struct wined3d_context_gl *context_gl; @@ -1040,7 +1050,7 @@ static void wined3d_swapchain_vk_set_swap_interval(struct wined3d_swapchain_vk * static VkResult wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain_vk, struct wined3d_context_vk *context_vk, const RECT *src_rect, const RECT *dst_rect, unsigned int swap_interval) { - struct wined3d_texture_vk *back_buffer_vk = wined3d_texture_vk(swapchain_vk->s.back_buffers[0]); + struct wined3d_texture_vk *back_buffer_vk = wined3d_texture_vk(swapchain_vk->s.back_buffers[0].texture); struct wined3d_device_vk *device_vk = wined3d_device_vk(swapchain_vk->s.device); const struct wined3d_swapchain_desc *desc = &swapchain_vk->s.state.desc; const struct wined3d_vk_info *vk_info = context_vk->vk_info; @@ -1168,11 +1178,13 @@ static VkResult wined3d_swapchain_vk_blit(struct wined3d_swapchain_vk *swapchain static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, struct wined3d_context_vk *context_vk) { struct wined3d_texture_sub_resource *sub_resource; + struct wined3d_backbuffer *backbuffer, *backbuffer_prev; struct wined3d_texture_vk *texture, *texture_prev; struct wined3d_image_vk image0; VkDescriptorImageInfo vk_info0; VkImageLayout vk_layout0; uint32_t bind_mask0; + HRGN dirty_region0; DWORD locations0; unsigned int i;
@@ -1181,9 +1193,11 @@ static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, str if (swapchain->state.desc.backbuffer_count < 2) return;
- texture_prev = wined3d_texture_vk(swapchain->back_buffers[0]); + backbuffer_prev = &swapchain->back_buffers[0]; + texture_prev = wined3d_texture_vk(backbuffer_prev->texture);
/* Back buffer 0 is already in the draw binding. */ + dirty_region0 = backbuffer_prev->dirty_region; image0 = texture_prev->image; vk_layout0 = texture_prev->layout; bind_mask0 = texture_prev->bind_mask; @@ -1192,12 +1206,14 @@ static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, str
for (i = 1; i < swapchain->state.desc.backbuffer_count; ++i) { - texture = wined3d_texture_vk(swapchain->back_buffers[i]); + backbuffer = &swapchain->back_buffers[i]; + texture = wined3d_texture_vk(backbuffer->texture); sub_resource = &texture->t.sub_resources[0];
if (!(sub_resource->locations & supported_locations)) wined3d_texture_load_location(&texture->t, 0, &context_vk->c, texture->t.resource.draw_binding);
+ backbuffer_prev->dirty_region = backbuffer->dirty_region; texture_prev->image = texture->image; texture_prev->layout = texture->layout; texture_prev->bind_mask = texture->bind_mask; @@ -1206,9 +1222,11 @@ static void wined3d_swapchain_vk_rotate(struct wined3d_swapchain *swapchain, str wined3d_texture_validate_location(&texture_prev->t, 0, sub_resource->locations & supported_locations); wined3d_texture_invalidate_location(&texture_prev->t, 0, ~(sub_resource->locations & supported_locations));
+ backbuffer_prev = backbuffer; texture_prev = texture; }
+ backbuffer_prev->dirty_region = dirty_region0; texture_prev->image = image0; texture_prev->layout = vk_layout0; texture_prev->bind_mask = bind_mask0; @@ -1224,7 +1242,7 @@ static void swapchain_vk_present(struct wined3d_swapchain *swapchain, const RECT const RECT *dst_rect, unsigned int swap_interval, uint32_t flags) { struct wined3d_swapchain_vk *swapchain_vk = wined3d_swapchain_vk(swapchain); - struct wined3d_texture *back_buffer = swapchain->back_buffers[0]; + struct wined3d_texture *back_buffer = swapchain->back_buffers[0].texture; struct wined3d_context_vk *context_vk; VkResult vr; HRESULT hr; @@ -1324,7 +1342,7 @@ static void swapchain_gdi_present(struct wined3d_swapchain *swapchain, HDC dc;
front = &swapchain->front_buffer->dc_info[0]; - back = &swapchain->back_buffers[0]->dc_info[0]; + back = &swapchain->back_buffers[0].texture->dc_info[0];
/* Flip the surface data. */ dc = front->dc; @@ -1334,13 +1352,13 @@ static void swapchain_gdi_present(struct wined3d_swapchain *swapchain,
front->dc = back->dc; front->bitmap = back->bitmap; - swapchain->front_buffer->resource.heap_pointer = swapchain->back_buffers[0]->resource.heap_pointer; - swapchain->front_buffer->resource.heap_memory = swapchain->back_buffers[0]->resource.heap_memory; + swapchain->front_buffer->resource.heap_pointer = swapchain->back_buffers[0].texture->resource.heap_pointer; + swapchain->front_buffer->resource.heap_memory = swapchain->back_buffers[0].texture->resource.heap_memory;
back->dc = dc; back->bitmap = bitmap; - swapchain->back_buffers[0]->resource.heap_pointer = heap_pointer; - swapchain->back_buffers[0]->resource.heap_memory = heap_memory; + swapchain->back_buffers[0].texture->resource.heap_pointer = heap_pointer; + swapchain->back_buffers[0].texture->resource.heap_memory = heap_memory;
SetRect(&swapchain->front_buffer_update, 0, 0, swapchain->front_buffer->resource.width, @@ -1608,7 +1626,7 @@ static HRESULT wined3d_swapchain_init(struct wined3d_swapchain *swapchain, struc for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i) { TRACE("Creating back buffer %u.\n", i); - if (FAILED(hr = swapchain_create_texture(swapchain, false, false, &swapchain->back_buffers[i]))) + if (FAILED(hr = swapchain_create_texture(swapchain, false, false, &swapchain->back_buffers[i].texture))) { WARN("Failed to create back buffer %u, hr %#lx.\n", i, hr); swapchain->state.desc.backbuffer_count = i; @@ -1666,11 +1684,12 @@ err: { for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i) { - if (swapchain->back_buffers[i]) + if (swapchain->back_buffers[i].texture) { - wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); - wined3d_texture_decref(swapchain->back_buffers[i]); + wined3d_texture_set_swapchain(swapchain->back_buffers[i].texture, NULL); + wined3d_texture_decref(swapchain->back_buffers[i].texture); } + // No Present possible, no need to check and free dirty HRGN } free(swapchain->back_buffers); } @@ -1827,7 +1846,7 @@ void swapchain_update_draw_bindings(struct wined3d_swapchain *swapchain)
for (i = 0; i < swapchain->state.desc.backbuffer_count; ++i) { - wined3d_resource_update_draw_binding(&swapchain->back_buffers[i]->resource); + wined3d_resource_update_draw_binding(&swapchain->back_buffers[i].texture->resource); } }
@@ -2019,12 +2038,18 @@ HRESULT CDECL wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapcha
for (i = 0; i < desc->backbuffer_count; ++i) { + struct wined3d_backbuffer *backbuffer = &swapchain->back_buffers[i]; if (FAILED(hr = swapchain_create_texture(swapchain, false, false, &new_texture))) return hr; - wined3d_texture_set_swapchain(swapchain->back_buffers[i], NULL); - if (wined3d_texture_decref(swapchain->back_buffers[i])) - ERR("Something's still holding back buffer %u (%p).\n", i, swapchain->back_buffers[i]); - swapchain->back_buffers[i] = new_texture; + wined3d_texture_set_swapchain(backbuffer->texture, NULL); + if (wined3d_texture_decref(backbuffer->texture)) + ERR("Something's still holding back buffer %u (%p).\n", i, backbuffer->texture); + backbuffer->texture = new_texture; + if (backbuffer->dirty_region) + { + DeleteObject(backbuffer->dirty_region); + backbuffer->dirty_region = NULL; + } } }
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c index deb4304c282..715e883020a 100644 --- a/dlls/wined3d/texture.c +++ b/dlls/wined3d/texture.c @@ -128,7 +128,7 @@ GLenum wined3d_texture_get_gl_buffer(const struct wined3d_texture *texture) return GL_FRONT; }
- if (texture == swapchain->back_buffers[0]) + if (texture == swapchain->back_buffers[0].texture) { TRACE("Returning GL_BACK.\n"); return GL_BACK; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 7b2ef0d4b7f..7bcd37651de 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -4080,6 +4080,12 @@ struct wined3d_swapchain_ops void (*swapchain_frontbuffer_updated)(struct wined3d_swapchain *swapchain); };
+struct wined3d_backbuffer +{ + struct wined3d_texture *texture; + HRGN dirty_region; +}; + struct wined3d_swapchain { LONG ref; @@ -4088,7 +4094,7 @@ struct wined3d_swapchain const struct wined3d_swapchain_ops *swapchain_ops; struct wined3d_device *device;
- struct wined3d_texture **back_buffers; + struct wined3d_backbuffer *back_buffers; struct wined3d_texture *front_buffer; struct wined3d_gamma_ramp orig_gamma; bool reapply_mode;
From: Andrew Boyarshin andrew.boyarshin@gmail.com
--- dlls/d3d8/swapchain.c | 2 +- dlls/d3d9/device.c | 4 +- dlls/d3d9/swapchain.c | 2 +- dlls/ddraw/surface.c | 2 +- dlls/dxgi/swapchain.c | 15 +- dlls/dxgi/tests/dxgi.c | 210 ++++++++--------- dlls/wined3d/surface.c | 2 +- dlls/wined3d/swapchain.c | 476 +++++++++++++++++++++++++++++++++++++- dlls/wined3d/wined3d.spec | 3 +- include/wine/wined3d.h | 12 +- 10 files changed, 612 insertions(+), 116 deletions(-)
diff --git a/dlls/d3d8/swapchain.c b/dlls/d3d8/swapchain.c index 433da09d04b..8f34ea4ccdb 100644 --- a/dlls/d3d8/swapchain.c +++ b/dlls/d3d8/swapchain.c @@ -97,7 +97,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH d3d8_swapchain_Present(IDirect3DSwapChai if (dirty_region) FIXME("Ignoring dirty_region %p.\n", dirty_region);
- return wined3d_swapchain_present(swapchain->wined3d_swapchain, + return wined3d_swapchain_present_legacy(swapchain->wined3d_swapchain, src_rect, dst_rect, dst_window_override, swapchain->swap_interval, 0); }
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 5f59d10079d..5235a6c663e 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -1343,7 +1343,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_Present(IDirect3DDevice9Ex * for (i = 0; i < device->implicit_swapchain_count; ++i) { swapchain = wined3d_swapchain_get_parent(device->implicit_swapchains[i]); - if (FAILED(hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, + if (FAILED(hr = wined3d_swapchain_present_legacy(swapchain->wined3d_swapchain, src_rect, dst_rect, dst_window_override, swapchain->swap_interval, 0))) { wined3d_mutex_unlock(); @@ -4266,7 +4266,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_device_PresentEx(IDirect3DDevice9Ex for (i = 0; i < device->implicit_swapchain_count; ++i) { swapchain = wined3d_swapchain_get_parent(device->implicit_swapchains[i]); - if (FAILED(hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, + if (FAILED(hr = wined3d_swapchain_present_legacy(swapchain->wined3d_swapchain, src_rect, dst_rect, dst_window_override, swapchain->swap_interval, flags))) { wined3d_mutex_unlock(); diff --git a/dlls/d3d9/swapchain.c b/dlls/d3d9/swapchain.c index e87b8627ba3..97bd1c244ca 100644 --- a/dlls/d3d9/swapchain.c +++ b/dlls/d3d9/swapchain.c @@ -150,7 +150,7 @@ static HRESULT WINAPI DECLSPEC_HOTPATCH d3d9_swapchain_Present(IDirect3DSwapChai if (dirty_region) FIXME("Ignoring dirty_region %p.\n", dirty_region);
- return wined3d_swapchain_present(swapchain->wined3d_swapchain, + return wined3d_swapchain_present_legacy(swapchain->wined3d_swapchain, src_rect, dst_rect, dst_window_override, swapchain->swap_interval, flags); }
diff --git a/dlls/ddraw/surface.c b/dlls/ddraw/surface.c index 545c76738cd..8d68c579e3a 100644 --- a/dlls/ddraw/surface.c +++ b/dlls/ddraw/surface.c @@ -139,7 +139,7 @@ HRESULT ddraw_surface_update_frontbuffer(struct ddraw_surface *surface, ddraw_surface_get_any_texture(surface, DDRAW_SURFACE_READ), surface->sub_resource_idx, rect, 0, NULL, WINED3D_TEXF_POINT)) && swap_interval) { - hr = wined3d_swapchain_present(ddraw->wined3d_swapchain, rect, rect, NULL, swap_interval, 0); + hr = wined3d_swapchain_present_legacy(ddraw->wined3d_swapchain, rect, rect, NULL, swap_interval, 0); ddraw->flags |= DDRAW_SWAPPED; } return hr; diff --git a/dlls/dxgi/swapchain.c b/dlls/dxgi/swapchain.c index fd790cc7fe2..347567d3268 100644 --- a/dlls/dxgi/swapchain.c +++ b/dlls/dxgi/swapchain.c @@ -317,6 +317,7 @@ static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, unsigned int sync_interval, unsigned int flags, const DXGI_PRESENT_PARAMETERS *dxgi_parameters) { HRESULT hr; + struct wined3d_present_parameters wined3d_parameters;
if (sync_interval > 4) { @@ -335,9 +336,19 @@ static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, return S_OK; }
+ wined3d_parameters.swapchain = swapchain->wined3d_swapchain; + wined3d_parameters.swap_interval = sync_interval; + wined3d_parameters.flags = 0; + if (dxgi_parameters && dxgi_parameters->DirtyRectsCount && dxgi_parameters->pDirtyRects) { - FIXME("Ignored %u present dirty rectangles at %p ([0] = %s).\n", dxgi_parameters->DirtyRectsCount, dxgi_parameters->pDirtyRects, wine_dbgstr_rect(&dxgi_parameters->pDirtyRects[0])); + wined3d_parameters.dirty_rectangle_count = dxgi_parameters->DirtyRectsCount; + wined3d_parameters.dirty_rectangles = dxgi_parameters->pDirtyRects; + } + else + { + wined3d_parameters.dirty_rectangle_count = 0; + wined3d_parameters.dirty_rectangles = NULL; }
if (dxgi_parameters && dxgi_has_scroll_present_parameters(dxgi_parameters)) @@ -356,7 +367,7 @@ static HRESULT d3d11_swapchain_present(struct d3d11_swapchain *swapchain, FIXME("Ignored present %s scroll of %s rectangle.\n", wine_dbgstr_point(dxgi_parameters->pScrollOffset), wine_dbgstr_rect(dxgi_parameters->pScrollRect)); }
- if (SUCCEEDED(hr = wined3d_swapchain_present(swapchain->wined3d_swapchain, NULL, NULL, NULL, sync_interval, 0))) + if (SUCCEEDED(hr = wined3d_swapchain_present(&wined3d_parameters))) InterlockedIncrement(&swapchain->present_count); return hr; } diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c index 812695c2f99..ed968aa46a6 100644 --- a/dlls/dxgi/tests/dxgi.c +++ b/dlls/dxgi/tests/dxgi.c @@ -8965,7 +8965,7 @@ static void test_partial_present_grid_impl(struct test_partial_present_grid_para const DWORD color_dword = PALETTE_RGBA_DWORD[palette_index];
for (UINT k = 0; k < buffer_count; ++k) - flaky_wine check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles); + check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles);
ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, color_float);
@@ -8986,7 +8986,7 @@ static void test_partial_present_grid_impl(struct test_partial_present_grid_para backbuffer_info[k] = backbuffer_info[k + 1];
for (UINT k = 0; k < buffer_count; ++k) - flaky_wine check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles); + check_texture(backbuffers[k], backbuffer_info[k]->background, buffer_count, backbuffer_info[k]->rectangles); } }
@@ -9105,60 +9105,60 @@ static void test_partial_present_scroll_impl(struct test_partial_present_common_ check_full(backbuffer_0, BLACK); check_full(backbuffer_1, RED);
- todo_wine check_color(backbuffer_2, 5, 5, RED); - todo_wine check_color(backbuffer_2, 20, 20, RED); - todo_wine check_color(backbuffer_2, 49, 29, RED); - todo_wine check_color(backbuffer_2, 49, 39, RED); - flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ - todo_wine check_color(backbuffer_2, 99, 29, RED); - todo_wine check_color(backbuffer_2, 99, 39, RED); - flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 199, 59, RED); - todo_wine check_color(backbuffer_2, 399, 59, RED); - flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 9, 399, RED); - todo_wine check_color(backbuffer_2, 9, 419, RED); - todo_wine check_color(backbuffer_2, 599, 399, RED); - todo_wine check_color(backbuffer_2, 599, 419, RED); + check_color(backbuffer_2, 5, 5, RED); + check_color(backbuffer_2, 20, 20, RED); + check_color(backbuffer_2, 49, 29, RED); + check_color(backbuffer_2, 49, 39, RED); + check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + check_color(backbuffer_2, 99, 29, RED); + check_color(backbuffer_2, 99, 39, RED); + check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 199, 59, RED); + check_color(backbuffer_2, 399, 59, RED); + check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 9, 399, RED); + check_color(backbuffer_2, 9, 419, RED); + check_color(backbuffer_2, 599, 399, RED); + check_color(backbuffer_2, 599, 419, RED);
ID3D11DeviceContext_ClearRenderTargetView(context, backbuffer_0_rtv, blue);
check_full(backbuffer_0, BLUE); check_full(backbuffer_1, RED);
- todo_wine check_color(backbuffer_2, 5, 5, RED); - todo_wine check_color(backbuffer_2, 20, 20, RED); - todo_wine check_color(backbuffer_2, 49, 29, RED); - todo_wine check_color(backbuffer_2, 49, 39, RED); - flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ - todo_wine check_color(backbuffer_2, 99, 29, RED); - todo_wine check_color(backbuffer_2, 99, 39, RED); - flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 199, 59, RED); - todo_wine check_color(backbuffer_2, 399, 59, RED); - flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 9, 399, RED); - todo_wine check_color(backbuffer_2, 9, 419, RED); - todo_wine check_color(backbuffer_2, 599, 399, RED); - todo_wine check_color(backbuffer_2, 599, 419, RED); + check_color(backbuffer_2, 5, 5, RED); + check_color(backbuffer_2, 20, 20, RED); + check_color(backbuffer_2, 49, 29, RED); + check_color(backbuffer_2, 49, 39, RED); + check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + check_color(backbuffer_2, 99, 29, RED); + check_color(backbuffer_2, 99, 39, RED); + check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 199, 59, RED); + check_color(backbuffer_2, 399, 59, RED); + check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 9, 399, RED); + check_color(backbuffer_2, 9, 419, RED); + check_color(backbuffer_2, 599, 399, RED); + check_color(backbuffer_2, 599, 419, RED);
present_params.DirtyRectsCount = ARRAYSIZE(dirty_rects_blue); present_params.pDirtyRects = dirty_rects_blue; @@ -9173,51 +9173,51 @@ static void test_partial_present_scroll_impl(struct test_partial_present_common_
check_full(backbuffer_0, RED);
- todo_wine check_color(backbuffer_1, 5, 5, RED); - todo_wine check_color(backbuffer_1, 20, 20, RED); - todo_wine check_color(backbuffer_1, 49, 29, RED); - todo_wine check_color(backbuffer_1, 49, 39, RED); - flaky_wine check_colors(backbuffer_1, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_1, 49, 79, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_1, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ - todo_wine check_color(backbuffer_1, 99, 29, RED); - todo_wine check_color(backbuffer_1, 99, 39, RED); - flaky_wine check_colors(backbuffer_1, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_1, 99, 79, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_1, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_1, 199, 59, RED); - todo_wine check_color(backbuffer_1, 399, 59, RED); - flaky_wine check_colors(backbuffer_1, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_1, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_1, 199, 279, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_1, 399, 279, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_1, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ - flaky_wine check_colors(backbuffer_1, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_1, 9, 399, RED); - todo_wine check_color(backbuffer_1, 9, 419, RED); - todo_wine check_color(backbuffer_1, 599, 399, RED); - todo_wine check_color(backbuffer_1, 599, 419, RED); - - todo_wine check_color(backbuffer_2, 5, 5, RED); - todo_wine check_color(backbuffer_2, 20, 20, RED); + check_color(backbuffer_1, 5, 5, RED); + check_color(backbuffer_1, 20, 20, RED); + check_color(backbuffer_1, 49, 29, RED); + check_color(backbuffer_1, 49, 39, RED); + check_colors(backbuffer_1, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_1, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_1, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + check_color(backbuffer_1, 99, 29, RED); + check_color(backbuffer_1, 99, 39, RED); + check_colors(backbuffer_1, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_1, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_1, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_1, 199, 59, RED); + check_color(backbuffer_1, 399, 59, RED); + check_colors(backbuffer_1, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_1, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_1, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_1, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_1, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + check_colors(backbuffer_1, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_1, 9, 399, RED); + check_color(backbuffer_1, 9, 419, RED); + check_color(backbuffer_1, 599, 399, RED); + check_color(backbuffer_1, 599, 419, RED); + + check_color(backbuffer_2, 5, 5, RED); + check_color(backbuffer_2, 20, 20, RED); flaky_wine check_colors(backbuffer_2, 49, 29, RED, RED, RED, GREEN); /* top-left corner */ flaky_wine check_colors(backbuffer_2, 49, 39, RED, GREEN, RED, BLUE); /* left side, green-blue edge */ flaky_wine check_colors(backbuffer_2, 49, 49, RED, BLUE, RED, BLUE); /* left side */ flaky_wine check_colors(backbuffer_2, 49, 79, RED, BLUE, RED, RED); /* bottom-left corner */ - todo_wine check_color(backbuffer_2, 49, 99, RED); + flaky_wine check_color(backbuffer_2, 49, 99, RED); flaky_wine check_colors(backbuffer_2, 99, 29, RED, RED, GREEN, RED); /* top-right corner */ flaky_wine check_colors(backbuffer_2, 99, 39, GREEN, RED, BLUE, RED); /* right side, green-blue edge */ flaky_wine check_colors(backbuffer_2, 99, 49, BLUE, RED, BLUE, RED); /* right side */ flaky_wine check_colors(backbuffer_2, 99, 79, BLUE, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 99, 99, RED); + flaky_wine check_color(backbuffer_2, 99, 99, RED); flaky_wine check_colors(backbuffer_2, 199, 59, RED, RED, RED, GREEN); /* top-left corner */ flaky_wine check_colors(backbuffer_2, 399, 59, RED, RED, GREEN, RED); /* top-right corner */ flaky_wine check_colors(backbuffer_2, 199, 79, RED, GREEN, RED, GREEN); /* left side */ flaky_wine check_colors(backbuffer_2, 399, 79, GREEN, RED, GREEN, RED); /* right side */ flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, RED); /* bottom-left corner */ flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 199, 299, RED); - todo_wine check_color(backbuffer_2, 399, 299, RED); + flaky_wine check_color(backbuffer_2, 199, 299, RED); + flaky_wine check_color(backbuffer_2, 399, 299, RED); flaky_wine check_colors(backbuffer_2, 9, 399, RED, RED, RED, BLUE); /* top-left corner */ flaky_wine check_colors(backbuffer_2, 9, 419, RED, BLUE, RED, RED); /* bottom-left corner */ flaky_wine check_colors(backbuffer_2, 599, 399, RED, RED, BLUE, RED); /* top-right corner */ @@ -9232,30 +9232,30 @@ static void test_partial_present_scroll_impl(struct test_partial_present_common_ check_full(backbuffer_0, BLUE); check_full(backbuffer_1, RED);
- todo_wine check_color(backbuffer_2, 5, 5, RED); - todo_wine check_color(backbuffer_2, 20, 20, RED); - todo_wine check_color(backbuffer_2, 49, 29, RED); - todo_wine check_color(backbuffer_2, 49, 39, RED); - flaky_wine check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ - todo_wine check_color(backbuffer_2, 99, 29, RED); - todo_wine check_color(backbuffer_2, 99, 39, RED); - flaky_wine check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 199, 59, RED); - todo_wine check_color(backbuffer_2, 399, 59, RED); - flaky_wine check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ - flaky_wine check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ - flaky_wine check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ - flaky_wine check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ - flaky_wine check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ - todo_wine check_color(backbuffer_2, 9, 399, RED); - todo_wine check_color(backbuffer_2, 9, 419, RED); - todo_wine check_color(backbuffer_2, 599, 399, RED); - todo_wine check_color(backbuffer_2, 599, 419, RED); + check_color(backbuffer_2, 5, 5, RED); + check_color(backbuffer_2, 20, 20, RED); + check_color(backbuffer_2, 49, 29, RED); + check_color(backbuffer_2, 49, 39, RED); + check_colors(backbuffer_2, 49, 49, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 49, 79, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 49, 99, RED, GREEN, RED, RED); /* bottom-left corner */ + check_color(backbuffer_2, 99, 29, RED); + check_color(backbuffer_2, 99, 39, RED); + check_colors(backbuffer_2, 99, 49, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 99, 79, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 99, 99, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 199, 59, RED); + check_color(backbuffer_2, 399, 59, RED); + check_colors(backbuffer_2, 199, 79, RED, RED, RED, GREEN); /* top-left corner */ + check_colors(backbuffer_2, 399, 79, RED, RED, GREEN, RED); /* top-right corner */ + check_colors(backbuffer_2, 199, 279, RED, GREEN, RED, GREEN); /* left side */ + check_colors(backbuffer_2, 399, 279, GREEN, RED, GREEN, RED); /* right side */ + check_colors(backbuffer_2, 199, 299, RED, GREEN, RED, RED); /* bottom-left corner */ + check_colors(backbuffer_2, 399, 299, GREEN, RED, RED, RED); /* bottom-right corner */ + check_color(backbuffer_2, 9, 399, RED); + check_color(backbuffer_2, 9, 419, RED); + check_color(backbuffer_2, 599, 399, RED); + check_color(backbuffer_2, 599, 419, RED); }
ID3D11RenderTargetView_Release(backbuffer_0_rtv); diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 7f519cb553e..7faa5e8356e 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -1601,7 +1601,7 @@ HRESULT texture2d_blt(struct wined3d_texture *dst_texture, unsigned int dst_sub_ /* Set the swap effect to COPY, we don't want the backbuffer to become * undefined. */ dst_swapchain->state.desc.swap_effect = WINED3D_SWAP_EFFECT_COPY; - wined3d_swapchain_present(dst_swapchain, NULL, NULL, + wined3d_swapchain_present_legacy(dst_swapchain, NULL, NULL, dst_swapchain->win_handle, dst_swapchain->swap_interval, 0); dst_swapchain->state.desc.swap_effect = swap_effect;
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c index 9156d74beef..e27b4a1839a 100644 --- a/dlls/wined3d/swapchain.c +++ b/dlls/wined3d/swapchain.c @@ -27,6 +27,205 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d); WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
+static const char *wine_dbgstr_rgn( HRGN hrgn ) +{ + DWORD i, size; + RGNDATA *data = NULL; + RECT *rect; + char buffer[200]; + int buffer_position = 0; + + if (!hrgn) return "(null)"; + + if (!(size = GetRegionData(hrgn, 0, NULL))) return "(ERROR)"; + if (!(data = malloc(size))) return "(NOMEM)"; + GetRegionData(hrgn, size, data); + + if (buffer_position < ARRAYSIZE(buffer)) + buffer_position += snprintf(buffer + buffer_position, ARRAYSIZE(buffer) - buffer_position, "{"); + + for (i = 0, rect = (RECT *) data->Buffer; i < data->rdh.nCount; ++i, ++rect) + { + if (i != 0 && buffer_position < ARRAYSIZE(buffer)) + buffer_position += snprintf(buffer + buffer_position, ARRAYSIZE(buffer) - buffer_position, ", "); + + if (buffer_position < ARRAYSIZE(buffer)) + buffer_position += snprintf(buffer + buffer_position, ARRAYSIZE(buffer) - buffer_position, "%s", wine_dbgstr_rect(rect)); + } + + free(data); + + if (buffer_position < ARRAYSIZE(buffer)) + buffer_position += snprintf(buffer + buffer_position, ARRAYSIZE(buffer) - buffer_position, "}"); + + buffer[ARRAYSIZE(buffer) - 1] = 0; + return __wine_dbg_strdup(buffer); +} + +static void region_set(HRGN *region, const RECT *rect) +{ + HRGN hrgn = *region; + + TRACE("region %p %s, rect %s.\n", region, wine_dbgstr_rgn(hrgn), wine_dbgstr_rect(rect)); + + if (hrgn) + { + if (!SetRectRgn(hrgn, rect->left, rect->top, rect->right, rect->bottom)) + ERR("Failed to update region %p with %s.\n", hrgn, wine_dbgstr_rect(rect)); + } + else + { + *region = hrgn = CreateRectRgnIndirect(rect); + if (!hrgn) + ERR("Failed to create region from %s.\n", wine_dbgstr_rect(rect)); + } +} + +static INT region_combine_region(HRGN *region, HRGN other, INT mode) +{ + HRGN hrgn = *region; + INT result; + + TRACE("region %p %p %s, other %p %s, mode %d.\n", + region, hrgn, wine_dbgstr_rgn(hrgn), other, wine_dbgstr_rgn(other), mode); + + if (hrgn && other) + { + /* CombineRgn only works well with non-NULL destination and sources */ + result = CombineRgn(hrgn, hrgn, other, mode); + } + else if (hrgn) + { + /* lhs != NULL, rhs == NULL */ + switch (mode) + { + case RGN_AND: + if (!SetRectRgn(hrgn, 0, 0, 0, 0)) + { + ERR("Failed to clear region %p.\n", hrgn); + return ERROR; + } + return NULLREGION; + case RGN_OR: + case RGN_XOR: + case RGN_DIFF: + case RGN_COPY: + result = CombineRgn(hrgn, hrgn, NULL, RGN_COPY); + break; + default: + ERR("Invalid CombineRgn mode %d.\n", mode); + return ERROR; + } + } + else if (other) + { + /* lhs == NULL, rhs != NULL */ + switch (mode) + { + case RGN_AND: + case RGN_DIFF: + case RGN_COPY: + return NULLREGION; + case RGN_OR: + case RGN_XOR: + *region = hrgn = CreateRectRgn(0, 0, 0, 0); + result = CombineRgn(hrgn, other, NULL, RGN_COPY); + break; + default: + ERR("Invalid CombineRgn mode %d.\n", mode); + return ERROR; + } + } + else + { + /* lhs == NULL, rhs == NULL */ + return NULLREGION; + } + if (result == ERROR) + { + ERR("CombineRgn(%p, %p, %d) failed.\n", *region, other, mode); + } + return result; +} + +static INT region_combine_rect(HRGN *region, const RECT *other, INT mode) +{ + HRGN hrgn = *region; + INT result; + + TRACE("region %p %p %s, other %s, mode %d.\n", + region, hrgn, wine_dbgstr_rgn(hrgn), wine_dbgstr_rect(other), mode); + + if (hrgn && !IsRectEmpty(other)) + { + /* lhs != NULL, rhs != NULL */ + HRGN other_region = CreateRectRgnIndirect(other); + if (!other_region) + { + ERR("Failed to create region from %s.\n", wine_dbgstr_rect(other)); + return ERROR; + } + + result = CombineRgn(hrgn, hrgn, other_region, mode); + } + else if (hrgn) + { + /* lhs != NULL, rhs == NULL */ + switch (mode) + { + case RGN_AND: + if (!SetRectRgn(hrgn, 0, 0, 0, 0)) + { + ERR("Failed to clear region %p.\n", hrgn); + return ERROR; + } + return NULLREGION; + case RGN_OR: + case RGN_XOR: + case RGN_DIFF: + case RGN_COPY: + result = CombineRgn(hrgn, hrgn, NULL, RGN_COPY); + break; + default: + ERR("Invalid CombineRgn mode %d.\n", mode); + return ERROR; + } + } + else if (!IsRectEmpty(other)) + { + /* lhs == NULL, rhs != NULL */ + switch (mode) + { + case RGN_AND: + case RGN_DIFF: + case RGN_COPY: + return NULLREGION; + case RGN_OR: + case RGN_XOR: + *region = hrgn = CreateRectRgnIndirect(other); + if (!hrgn) + { + ERR("Failed to create region from %s.\n", wine_dbgstr_rect(other)); + return ERROR; + } + return SIMPLEREGION; + default: + ERR("Invalid CombineRgn mode %d.\n", mode); + return ERROR; + } + } + else + { + /* lhs == NULL, rhs == NULL */ + return NULLREGION; + } + if (result == ERROR) + { + ERR("CombineRgn(%p, %p, %d) failed.\n", *region, other, mode); + } + return result; +} + void wined3d_swapchain_cleanup(struct wined3d_swapchain *swapchain) { HRESULT hr; @@ -191,7 +390,7 @@ void CDECL wined3d_swapchain_set_window(struct wined3d_swapchain *swapchain, HWN swapchain->win_handle = window; }
-HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain, +HRESULT CDECL wined3d_swapchain_present_legacy(struct wined3d_swapchain *swapchain, const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, unsigned int swap_interval, uint32_t flags) { @@ -226,6 +425,8 @@ HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain, dst_rect = &d; }
+ region_set(&swapchain->back_buffers[0].dirty_region, src_rect); + wined3d_cs_emit_present(swapchain->device->cs, swapchain, src_rect, dst_rect, dst_window_override, swap_interval, flags);
@@ -234,6 +435,279 @@ HRESULT CDECL wined3d_swapchain_present(struct wined3d_swapchain *swapchain, return WINED3D_OK; }
+static HRESULT present_region_blit(struct wined3d_swapchain *swapchain, + struct wined3d_texture *src_texture, struct wined3d_texture *dst_texture, HRGN region) +{ + DWORD region_data_size_expected, region_data_size_actual; + RGNDATA *region_data = NULL; + struct wined3d_device_context *context; + HRESULT hr; + RECT bounds; + + TRACE("swapchain %p, src_texture %p, dst_texture %p, region %p %s.\n", + swapchain, src_texture, dst_texture, region, wine_dbgstr_rgn(region)); + + region_data_size_expected = GetRegionData(region, 0, NULL); + region_data = malloc(region_data_size_expected); + if (!region_data) + { + ERR("Failed to allocate %lu bytes.\n", region_data_size_expected); + hr = E_OUTOFMEMORY; + goto state_cleanup; + } + + region_data_size_actual = GetRegionData(region, region_data_size_expected, region_data); + if (!region_data_size_actual) + { + DWORD error = GetLastError(); + ERR("Failed to acquire region data, error %#lx.\n", error); + hr = HRESULT_FROM_WIN32(error); + goto state_cleanup; + } + + hr = S_OK; + context = wined3d_device_get_immediate_context(swapchain->device); + SetRect(&bounds, 0, 0, dst_texture->resource.width, dst_texture->resource.height); + + for (DWORD i = 0; i < region_data->rdh.nCount; ++i) + { + RECT dst_rect = ((const RECT *) region_data->Buffer)[i]; + RECT clipped_dst_rect; + RECT src_rect; + + if (!IntersectRect(&clipped_dst_rect, &dst_rect, &bounds)) + { + TRACE("Destination rect %s is completely out of bounds after clipping to %s.\n", + wine_dbgstr_rect(&dst_rect), wine_dbgstr_rect(&bounds)); + continue; + } + + if (!EqualRect(&dst_rect, &clipped_dst_rect)) + { + TRACE("Destination rect %s clipped to %s is %s.\n", + wine_dbgstr_rect(&dst_rect), wine_dbgstr_rect(&bounds), wine_dbgstr_rect(&clipped_dst_rect)); + dst_rect = clipped_dst_rect; + } + + src_rect = dst_rect; + + hr = wined3d_device_context_blt(context, dst_texture, 0, &dst_rect, src_texture, 0, &src_rect, WINED3D_BLT_RAW, NULL, WINED3D_TEXF_POINT); + if (FAILED(hr)) + { + ERR("Failed to blit region #%lu: %s -> %s.\n", i, wine_dbgstr_rect(&src_rect), wine_dbgstr_rect(&dst_rect)); + break; + } + } + +state_cleanup: + free(region_data); + return hr; +} + +HRESULT CDECL present_partial_compute_dirty(struct wined3d_present_parameters *parameters) +{ + struct wined3d_swapchain *swapchain = parameters->swapchain; + struct wined3d_swapchain_desc *desc = &swapchain->state.desc; + UINT backbuffer_count = desc->backbuffer_count; + struct wined3d_backbuffer *backbuffer_0 = &swapchain->back_buffers[0]; + struct wined3d_backbuffer *backbuffer_prev = &swapchain->back_buffers[backbuffer_count - 1]; + unsigned int backbuffer_width = desc->backbuffer_width; + unsigned int backbuffer_height = desc->backbuffer_height; + HRGN blt_region = NULL; + RECT backbuffer_rect; + INT region_kind; + + SetRect(&backbuffer_rect, 0, 0, backbuffer_width, backbuffer_height); + + if (parameters->dirty_rectangle_count) + { + if (backbuffer_0->dirty_region) + { + SetRectRgn(backbuffer_0->dirty_region, 0, 0, 0, 0); + } + + for (UINT i = 0; i < parameters->dirty_rectangle_count; ++i) + { + RECT dirty_rect = parameters->dirty_rectangles[i]; + region_combine_rect(&backbuffer_0->dirty_region, &dirty_rect, RGN_OR); + } + } + else + { + region_set(&backbuffer_0->dirty_region, &backbuffer_rect); + } + + for (UINT i = 1; i < backbuffer_count; ++i) + { + struct wined3d_backbuffer *backbuffer = &swapchain->back_buffers[i]; + region_combine_region(&blt_region, backbuffer->dirty_region, RGN_OR); + } + + TRACE("dirty_other = %p %s\n", blt_region, wine_dbgstr_rgn(blt_region)); + TRACE("dirty_0 = %p %s\n", backbuffer_0->dirty_region, wine_dbgstr_rgn(backbuffer_0->dirty_region)); + + region_kind = region_combine_region(&blt_region, backbuffer_0->dirty_region, RGN_DIFF); + TRACE("blt_region = [%d] %p %s\n", region_kind, blt_region, wine_dbgstr_rgn(blt_region)); + + if (region_kind != NULLREGION) + present_region_blit(swapchain, backbuffer_prev->texture, backbuffer_0->texture, blt_region); + + if (blt_region) + DeleteObject(blt_region); + + return S_OK; +} + +void CDECL present_transform_dirty_rect(SIZE *swapchain, SIZE *client, RECT *src_rect, RECT *dst_rect) +{ + DOUBLE scale_x, scale_y; + if (!client->cx || !client->cy || !swapchain->cx || !swapchain->cy) + { + SetRectEmpty(dst_rect); + return; + } + + /* + * TODO: consider supporting scaling other that DXGI_SCALING_STRETCH: + * * DXGI_SCALING_NONE should copy src_rect to dst_rect + * * DXGI_SCALING_ASPECT_RATIO_STRETCH should apply letterboxing, a bit more complex than simple stretch + */ + scale_x = client->cx / swapchain->cx; + scale_y = client->cy / swapchain->cy; + dst_rect->left = floor(scale_x * src_rect->left); + dst_rect->top = floor(scale_y * src_rect->top); + dst_rect->right = ceil(scale_x * src_rect->right); + dst_rect->bottom = ceil(scale_y * src_rect->bottom); +} + +HRESULT CDECL present_partial_as_cs_op(struct wined3d_present_parameters *parameters, RECT *src_rect, RECT *dst_rect) +{ + struct wined3d_swapchain *swapchain = parameters->swapchain; + struct wined3d_swapchain_desc *desc = &swapchain->state.desc; + HRGN dirty_region_0 = swapchain->back_buffers[0].dirty_region; + DWORD region_data_size_expected, region_data_size_actual; + SIZE swapchain_size, client_size; + DWORD final_dirty_rectangle_count; + RECT client_rect; + RGNDATA *region_data = NULL; + HRESULT hr; + + swapchain_size.cx = desc->backbuffer_width; + swapchain_size.cy = desc->backbuffer_height; + GetClientRect(parameters->swapchain->win_handle, &client_rect); + client_size.cx = client_rect.right - client_rect.left; + client_size.cy = client_rect.bottom - client_rect.top; + + region_data_size_expected = GetRegionData(dirty_region_0, 0, NULL); + region_data = malloc(region_data_size_expected); + if (!region_data) + { + ERR("Failed to allocate %lu bytes.\n", region_data_size_expected); + hr = E_OUTOFMEMORY; + goto state_cleanup; + } + + region_data_size_actual = GetRegionData(dirty_region_0, region_data_size_expected, region_data); + if (!region_data_size_actual) + { + DWORD error = GetLastError(); + ERR("Failed to acquire region data, error %#lx.\n", error); + hr = HRESULT_FROM_WIN32(error); + goto state_cleanup; + } + + final_dirty_rectangle_count = region_data->rdh.nCount; + if (final_dirty_rectangle_count == 1) + { + RECT dirty_rect = ((const RECT *) region_data->Buffer)[0]; + + *src_rect = dirty_rect; + present_transform_dirty_rect(&swapchain_size, &client_size, src_rect, dst_rect); + } + else if (final_dirty_rectangle_count > 1) + { + FIXME("Multiple (%lu) dirty rectangles are not properly supported.\n", final_dirty_rectangle_count); + + *src_rect = region_data->rdh.rcBound; + present_transform_dirty_rect(&swapchain_size, &client_size, src_rect, dst_rect); + } + else + { + SetRectEmpty(src_rect); + SetRectEmpty(dst_rect); + } + + hr = S_OK; + +state_cleanup: + free(region_data); + + return hr; +} + +HRESULT CDECL wined3d_swapchain_present(struct wined3d_present_parameters *parameters) +{ + struct wined3d_swapchain *swapchain = parameters->swapchain; + uint32_t flags = parameters->flags; + struct wined3d_backbuffer *back_buffers; + HRESULT hr; + RECT src_rect, dst_rect; + + TRACE("swapchain %p, swap_interval %u, flags %#x, dirty_rectangle_count %u.\n", + swapchain, parameters->swap_interval, flags, parameters->dirty_rectangle_count); + + if (flags) + FIXME("Ignoring flags %#x.\n", flags); + + wined3d_mutex_lock(); + + back_buffers = swapchain->back_buffers; + if (!back_buffers) + { + WARN("Swapchain doesn't have a backbuffer, returning WINED3DERR_INVALIDCALL.\n"); + hr = WINED3DERR_INVALIDCALL; + goto cleanup; + } + + if (parameters->dirty_rectangle_count) + { + /* Partial presentation */ + if (FAILED(hr = present_partial_compute_dirty(parameters))) + { + goto cleanup; + } + + if (FAILED(hr = present_partial_as_cs_op(parameters, &src_rect, &dst_rect))) + { + goto cleanup; + } + } + else + { + /* Full presentation */ + struct wined3d_swapchain_desc *desc = &swapchain->state.desc; + struct wined3d_backbuffer *backbuffer_0 = &back_buffers[0]; + RECT backbuffer_rect; + + SetRect(&backbuffer_rect, 0, 0, desc->backbuffer_width, desc->backbuffer_height); + + region_set(&backbuffer_0->dirty_region, &backbuffer_rect); + + src_rect = backbuffer_rect; + GetClientRect(parameters->swapchain->win_handle, &dst_rect); + } + + wined3d_cs_emit_present(swapchain->device->cs, swapchain, &src_rect, + &dst_rect, NULL, parameters->swap_interval, flags); + + hr = WINED3D_OK; + +cleanup: + wined3d_mutex_unlock(); + + return hr; +} + HRESULT CDECL wined3d_swapchain_get_front_buffer_data(const struct wined3d_swapchain *swapchain, struct wined3d_texture *dst_texture, unsigned int sub_resource_idx) { diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec index 94e418ca885..ee2fda3fe8c 100644 --- a/dlls/wined3d/wined3d.spec +++ b/dlls/wined3d/wined3d.spec @@ -306,7 +306,8 @@ @ cdecl wined3d_swapchain_get_raster_status(ptr ptr) @ cdecl wined3d_swapchain_get_state(ptr) @ cdecl wined3d_swapchain_incref(ptr) -@ cdecl wined3d_swapchain_present(ptr ptr ptr ptr long long) +@ cdecl wined3d_swapchain_present_legacy(ptr ptr ptr ptr long long) +@ cdecl wined3d_swapchain_present(ptr) @ cdecl wined3d_swapchain_resize_buffers(ptr long long long long long long) @ cdecl wined3d_swapchain_set_gamma_ramp(ptr long ptr) @ cdecl wined3d_swapchain_set_palette(ptr ptr) diff --git a/include/wine/wined3d.h b/include/wine/wined3d.h index a3d449f14c6..be0de4c36b0 100644 --- a/include/wine/wined3d.h +++ b/include/wine/wined3d.h @@ -2318,6 +2318,15 @@ struct wined3d_streaming_buffer unsigned int bind_flags; };
+struct wined3d_present_parameters +{ + struct wined3d_swapchain *swapchain; + unsigned int swap_interval; + uint32_t flags; + uint32_t dirty_rectangle_count; + RECT *dirty_rectangles; +}; + void __stdcall wined3d_mutex_lock(void); void __stdcall wined3d_mutex_unlock(void);
@@ -2901,8 +2910,9 @@ HRESULT __cdecl wined3d_swapchain_get_raster_status(const struct wined3d_swapcha struct wined3d_raster_status *raster_status); struct wined3d_swapchain_state * __cdecl wined3d_swapchain_get_state(struct wined3d_swapchain *swapchain); ULONG __cdecl wined3d_swapchain_incref(struct wined3d_swapchain *swapchain); -HRESULT __cdecl wined3d_swapchain_present(struct wined3d_swapchain *swapchain, const RECT *src_rect, +HRESULT __cdecl wined3d_swapchain_present_legacy(struct wined3d_swapchain *swapchain, const RECT *src_rect, const RECT *dst_rect, HWND dst_window_override, unsigned int swap_interval, uint32_t flags); +HRESULT __cdecl wined3d_swapchain_present(struct wined3d_present_parameters *parameters); HRESULT __cdecl wined3d_swapchain_resize_buffers(struct wined3d_swapchain *swapchain, unsigned int buffer_count, unsigned int width, unsigned int height, enum wined3d_format_id format_id, enum wined3d_multisample_type multisample_type, unsigned int multisample_quality);