Signed-off-by: Paul Gofman gofmanp@gmail.com --- dlls/d3d9/device.c | 10 +++------- dlls/d3d9/tests/device.c | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/dlls/d3d9/device.c b/dlls/d3d9/device.c index 5e505b4cfa..5d14ce3cbc 100644 --- a/dlls/d3d9/device.c +++ b/dlls/d3d9/device.c @@ -3567,13 +3567,9 @@ static HRESULT WINAPI d3d9_device_SetStreamSource(IDirect3DDevice9Ex *iface, iface, stream_idx, buffer, offset, stride);
wined3d_mutex_lock(); - if (!stride) - { - unsigned int cur_offset; - - hr = wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, - &cur_offset, &stride); - } + if (!buffer_impl) + wined3d_device_get_stream_source(device->wined3d_device, stream_idx, &wined3d_buffer, + &offset, &stride);
if (!buffer_impl) wined3d_buffer = NULL; diff --git a/dlls/d3d9/tests/device.c b/dlls/d3d9/tests/device.c index 57521a5648..97435e91a5 100644 --- a/dlls/d3d9/tests/device.c +++ b/dlls/d3d9/tests/device.c @@ -3240,7 +3240,8 @@ cleanup:
static void test_set_stream_source(void) { - IDirect3DVertexBuffer9 *vb; + IDirect3DVertexBuffer9 *vb, *current_vb; + unsigned int offset, stride; IDirect3DDevice9 *device; IDirect3D9 *d3d9; ULONG refcount; @@ -3273,7 +3274,24 @@ static void test_set_stream_source(void) hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 3, 32); ok(hr == D3DERR_INVALIDCALL || hr == D3D_OK, "Got unexpected hr %#x.\n", hr); hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 4, 32); - ok(SUCCEEDED(hr), "Failed to set the stream source, hr %#x.\n", hr); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + + hr = IDirect3DDevice9_SetStreamSource(device, 0, NULL, 0, 0); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + hr = IDirect3DDevice9_GetStreamSource(device, 0, ¤t_vb, &offset, &stride); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(!current_vb, "Got unexpected vb %p.\n", current_vb); + ok(offset == 4, "Got unexpected offset %u.\n", offset); + ok(stride == 32, "Got unexpected stride %u.\n", stride); + + hr = IDirect3DDevice9_SetStreamSource(device, 0, vb, 0, 0); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + hr = IDirect3DDevice9_GetStreamSource(device, 0, ¤t_vb, &offset, &stride); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + ok(current_vb == vb, "Got unexpected vb %p.\n", current_vb); + IDirect3DVertexBuffer9_Release(current_vb); + ok(!offset, "Got unexpected offset %u.\n", offset); + ok(!stride, "Got unexpected stride %u.\n", stride);
/* Try to set the NULL buffer with an offset and stride 0 */ hr = IDirect3DDevice9_SetStreamSource(device, 0, NULL, 0, 0);
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=21161 Signed-off-by: Paul Gofman gofmanp@gmail.com --- dlls/d3d9/tests/stateblock.c | 48 ++++++++++++++++++++++++++++------ dlls/wined3d/device.c | 1 + dlls/wined3d/stateblock.c | 29 +++++++++++++++----- dlls/wined3d/wined3d_private.h | 1 + 4 files changed, 65 insertions(+), 14 deletions(-)
diff --git a/dlls/d3d9/tests/stateblock.c b/dlls/d3d9/tests/stateblock.c index 0983cf7b4f..59e5260e1c 100644 --- a/dlls/d3d9/tests/stateblock.c +++ b/dlls/d3d9/tests/stateblock.c @@ -67,6 +67,7 @@ struct state_test /* Apparently recorded stateblocks record and apply vertex declarations, * but don't capture them */ #define SB_QUIRK_RECORDED_VDECL_CAPTURE 0x00000001 +#define SB_QUIRK_STREAM_OFFSET_NOT_UPDATED 0x00000002
struct event_data { @@ -135,6 +136,8 @@ static void execute_test_chain(IDirect3DDevice9 *device, struct state_test *test { const void *data;
+ trace("event %u.\n", j); + /* Execute the next event handler (if available). */ if (event[j].event_fn) { @@ -349,16 +352,17 @@ static void execute_test_chain_all(IDirect3DDevice9 *device, struct state_test * struct event capture_reapply_stateblock_events[] = { {begin_stateblock, SB_DATA_NONE, SB_DATA_TEST_IN}, - {end_stateblock, SB_DATA_NONE, SB_DATA_NONE}, + {end_stateblock, SB_DATA_NONE, SB_DATA_DEFAULT}, {capture_stateblock, SB_DATA_DEFAULT, SB_DATA_TEST_IN}, - {apply_stateblock, SB_DATA_DEFAULT, SB_DATA_NONE, SB_QUIRK_RECORDED_VDECL_CAPTURE}, + {capture_stateblock, SB_DATA_TEST_IN, SB_DATA_DEFAULT}, + {apply_stateblock, SB_DATA_TEST_IN, SB_DATA_DEFAULT, SB_QUIRK_RECORDED_VDECL_CAPTURE}, };
struct event create_stateblock_capture_apply_all_events[] = { {create_stateblock_all, SB_DATA_DEFAULT, SB_DATA_TEST_IN}, {capture_stateblock, SB_DATA_TEST_ALL, SB_DATA_DEFAULT}, - {apply_stateblock, SB_DATA_TEST_ALL, SB_DATA_NONE}, + {apply_stateblock, SB_DATA_TEST_ALL, SB_DATA_NONE, SB_QUIRK_STREAM_OFFSET_NOT_UPDATED}, };
struct event create_stateblock_apply_all_events[] = @@ -433,7 +437,7 @@ static void execute_test_chain_all(IDirect3DDevice9 *device, struct state_test * execute_test_chain(device, test, ntests, apply_stateblock_events, 3, &arg);
trace("Running stateblock capture/reapply state tests\n"); - execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 4, &arg); + execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 5, &arg);
trace("Running create stateblock capture/apply all state tests\n"); execute_test_chain(device, test, ntests, create_stateblock_capture_apply_all_events, 3, &arg); @@ -749,7 +753,7 @@ static void light_check_data(IDirect3DDevice9 *device, const struct state_test * "Chain stage %u: expected get_light_result %#x, got %#x.\n", chain_stage, ldata->get_light_result, value.get_light_result);
- ok(value.enabled == ldata->enabled, + ok(!value.enabled == !ldata->enabled, "Chain stage %u: expected enabled %#x, got %#x.\n", chain_stage, ldata->enabled, value.enabled); ok(value.light.Type == ldata->light.Type, @@ -1666,6 +1670,7 @@ struct resource_test_data IDirect3DPixelShader9 *ps; IDirect3DIndexBuffer9 *ib; IDirect3DVertexBuffer9 **vb; + unsigned int stream_offset, stream_stride; IDirect3DTexture9 **tex; };
@@ -1682,6 +1687,7 @@ static void resource_apply_data(IDirect3DDevice9 *device, const struct state_tes { const struct resource_test_arg *arg = test->test_arg; const struct resource_test_data *d = data; + IDirect3DVertexBuffer9 *temp_vb = NULL; unsigned int i; HRESULT hr;
@@ -1699,10 +1705,26 @@ static void resource_apply_data(IDirect3DDevice9 *device, const struct state_tes
for (i = 0; i < arg->stream_count; ++i) { - hr = IDirect3DDevice9_SetStreamSource(device, i, d->vb[i], 0, 64); - ok(SUCCEEDED(hr), "SetStreamSource (%u, %p, 0, 64) returned %#x.\n", - i, d->vb[i], hr); + if (!d->vb[i]) + { + /* Use a non NULL vertex buffer to really set offset and stride and avoid leftover values. */ + if (!temp_vb) + { + hr = IDirect3DDevice9_CreateVertexBuffer(device, 64, D3DUSAGE_DYNAMIC, + 0, D3DPOOL_DEFAULT, &temp_vb, NULL); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + } + hr = IDirect3DDevice9_SetStreamSource(device, i, temp_vb, d->stream_offset, d->stream_stride); + ok(hr == D3D_OK, "Got unexpected hr %#x.\n", hr); + } + + hr = IDirect3DDevice9_SetStreamSource(device, i, d->vb[i], d->stream_offset, d->stream_stride); + ok(hr == D3D_OK, "Unexpected SetStreamSource result, i %u, vb %p, " + "stream_offset %u, stream_stride %u), hr %#x.\n", + i, d->vb[i], d->stream_offset, d->stream_stride, hr); } + if (temp_vb) + IDirect3DVertexBuffer9_Release(temp_vb);
for (i = 0; i < arg->tex_count; ++i) { @@ -1718,6 +1740,7 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes const struct resource_test_data *poison = &ctx->poison_data; const struct resource_test_arg *arg = test->test_arg; const struct resource_test_data *d = expected_data; + unsigned int expected_offset; unsigned int i; HRESULT hr; void *ptr; @@ -1771,6 +1794,7 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes IDirect3DIndexBuffer9_Release((IDirect3DIndexBuffer9 *)ptr); }
+ expected_offset = quirk & SB_QUIRK_STREAM_OFFSET_NOT_UPDATED ? 0 : d->stream_offset; for (i = 0; i < arg->stream_count; ++i) { ptr = poison->vb[i]; @@ -1778,6 +1802,8 @@ static void resource_check_data(IDirect3DDevice9 *device, const struct state_tes ok(SUCCEEDED(hr), "GetStreamSource (%u) returned %#x.\n", i, hr); ok(ptr == d->vb[i], "Chain stage %u, stream %u, expected vertex buffer %p, received %p.\n", chain_stage, i, d->vb[i], ptr); + ok(v == expected_offset, "Stream source offset %u, expected %u, stride %u.\n", v, expected_offset, w); + ok(w == d->stream_stride, "Stream source stride %u, expected %u.\n", w, d->stream_stride); if (SUCCEEDED(hr) && ptr) { IDirect3DIndexBuffer9_Release((IDirect3DVertexBuffer9 *)ptr); @@ -1811,6 +1837,8 @@ static void resource_default_data_init(struct resource_test_data *data, const st { data->vb[i] = NULL; } + data->stream_offset = 0; + data->stream_stride = 0; data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex)); for (i = 0; i < arg->tex_count; ++i) { @@ -1885,6 +1913,8 @@ static void resource_test_data_init(IDirect3DDevice9 *device, 0, D3DPOOL_DEFAULT, &data->vb[i], NULL); ok(SUCCEEDED(hr), "CreateVertexBuffer (%u) returned %#x.\n", i, hr); } + data->stream_offset = 4; + data->stream_stride = 64; data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex)); for (i = 0; i < arg->tex_count; ++i) { @@ -1908,6 +1938,8 @@ static void resource_poison_data_init(struct resource_test_data *data, const str { data->vb[i] = (IDirect3DVertexBuffer9 *)poison++; } + data->stream_offset = 16; + data->stream_stride = 128; data->tex = HeapAlloc(GetProcessHeap(), 0, arg->tex_count * sizeof(*data->tex)); for (i = 0; i < arg->tex_count; ++i) { diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c index 9556aeef83..517fd55c8c 100644 --- a/dlls/wined3d/device.c +++ b/dlls/wined3d/device.c @@ -1388,6 +1388,7 @@ HRESULT CDECL wined3d_device_set_stream_source(struct wined3d_device *device, UI wined3d_buffer_decref(device->update_stateblock_state->streams[stream_idx].buffer); device->update_stateblock_state->streams[stream_idx].buffer = buffer; device->update_stateblock_state->streams[stream_idx].stride = stride; + device->update_stateblock_state->streams[stream_idx].offset = offset;
if (device->recording) { diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c index 36239207ae..70a2f1ebc0 100644 --- a/dlls/wined3d/stateblock.c +++ b/dlls/wined3d/stateblock.c @@ -212,6 +212,7 @@ static void stateblock_savedstates_set_all(struct wined3d_saved_states *states,
/* Fixed size arrays */ states->streamSource = 0xffff; + states->stream_offset_ignore = FALSE; states->streamFreq = 0xffff; states->textures = 0xfffff; stateblock_set_bits(states->transform, WINED3D_HIGHEST_TRANSFORM_STATE + 1); @@ -916,13 +917,17 @@ void CDECL wined3d_stateblock_capture(struct wined3d_stateblock *stateblock) if (!(map & 1)) continue;
if (stateblock->stateblock_state.streams[i].stride != state->streams[i].stride + || stateblock->stateblock_state.streams[i].offset != state->streams[i].offset || stateblock->stateblock_state.streams[i].buffer != state->streams[i].buffer) { - TRACE("Updating stream source %u to %p, stride to %u.\n", - i, state->streams[i].buffer, - state->streams[i].stride); + TRACE("stateblock %p, stream source %u, buffer %p, stride %u, offset %u.\n", + stateblock, i, state->streams[i].buffer, state->streams[i].stride, + state->streams[i].offset);
stateblock->stateblock_state.streams[i].stride = state->streams[i].stride; + if (!stateblock->changed.stream_offset_ignore) + stateblock->stateblock_state.streams[i].offset = state->streams[i].offset; + if (state->streams[i].buffer) wined3d_buffer_incref(state->streams[i].buffer); if (stateblock->stateblock_state.streams[i].buffer) @@ -1211,18 +1216,24 @@ void CDECL wined3d_stateblock_apply(const struct wined3d_stateblock *stateblock) map = stateblock->changed.streamSource; for (i = 0; map; map >>= 1, ++i) { + struct wined3d_buffer *buffer; + unsigned int offset, stride; + if (!(map & 1)) continue;
- state->streams[i].stride = stateblock->stateblock_state.streams[i].stride; if (stateblock->stateblock_state.streams[i].buffer) wined3d_buffer_incref(stateblock->stateblock_state.streams[i].buffer); if (state->streams[i].buffer) wined3d_buffer_decref(state->streams[i].buffer); state->streams[i].buffer = stateblock->stateblock_state.streams[i].buffer;
+ offset = stateblock->stateblock_state.streams[i].offset; + stride = stateblock->stateblock_state.streams[i].stride; + + state->streams[i].stride = stride; + state->streams[i].offset = offset; wined3d_device_set_stream_source(device, i, - stateblock->stateblock_state.streams[i].buffer, - 0, stateblock->stateblock_state.streams[i].stride); + stateblock->stateblock_state.streams[i].buffer, offset, stride); }
map = stateblock->changed.streamFreq; @@ -1599,6 +1610,12 @@ static HRESULT stateblock_init(struct wined3d_stateblock *stateblock, stateblock_init_contained_states(stateblock); wined3d_stateblock_capture(stateblock);
+ /* According to the tests, stream offset is not updated in the captured state if + * the state was captured on state block creation. This is not the case for + * state blocks initialized with BeginStateBlock / EndStateBlock, multiple + * captures get stream offsets updated. */ + stateblock->changed.stream_offset_ignore = TRUE; + return WINED3D_OK; }
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index d8df79026a..60a69023c5 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -3641,6 +3641,7 @@ struct wined3d_saved_states { DWORD transform[(WINED3D_HIGHEST_TRANSFORM_STATE >> 5) + 1]; WORD streamSource; /* WINED3D_MAX_STREAMS, 16 */ + BOOL stream_offset_ignore; WORD streamFreq; /* WINED3D_MAX_STREAMS, 16 */ DWORD renderState[(WINEHIGHEST_RENDER_STATE >> 5) + 1]; DWORD textureState[WINED3D_MAX_TEXTURES]; /* WINED3D_HIGHEST_TEXTURE_STATE + 1, 18 */
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=50469
Your paranoid android.
=== debian9 (build log) ===
X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig)
=== debian9 (64 bit WoW report) ===
d3d9: device.c:4621: Test failed: Failed to reset device.
Report errors: d3d9:device has unaccounted for failure messages d3d9:device returned success despite having failures
=== debian9 (build log) ===
X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig)
On Wed, 3 Apr 2019 at 21:57, Paul Gofman gofmanp@gmail.com wrote:
@@ -433,7 +437,7 @@ static void execute_test_chain_all(IDirect3DDevice9 *device, struct state_test * execute_test_chain(device, test, ntests, apply_stateblock_events, 3, &arg);
trace("Running stateblock capture/reapply state tests\n");
- execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 4, &arg);
- execute_test_chain(device, test, ntests, capture_reapply_stateblock_events, 5, &arg);
We'll probably want ARRAY_SIZE there.
@@ -749,7 +753,7 @@ static void light_check_data(IDirect3DDevice9 *device, const struct state_test * "Chain stage %u: expected get_light_result %#x, got %#x.\n", chain_stage, ldata->get_light_result, value.get_light_result);
- ok(value.enabled == ldata->enabled,
- ok(!value.enabled == !ldata->enabled,
Is that an unrelated change? I remember us caring about the specific value GetLightEnable() returns, so the test was probably intentionally written this way.
@@ -3641,6 +3641,7 @@ struct wined3d_saved_states { DWORD transform[(WINED3D_HIGHEST_TRANSFORM_STATE >> 5) + 1]; WORD streamSource; /* WINED3D_MAX_STREAMS, 16 */
- BOOL stream_offset_ignore; WORD streamFreq; /* WINED3D_MAX_STREAMS, 16 */
Putting a BOOL between two WORDs really isn't ideal for structure packing. Rather than just moving the BOOL though, perhaps it makes more sense to invert its meaning, take a bit out of "padding", and add a "DWORD stream_offset : 1;" instead?
On 4/4/19 17:39, Henri Verbeet wrote:
@@ -749,7 +753,7 @@ static void light_check_data(IDirect3DDevice9 *device, const struct state_test *
"Chain stage %u: expected get_light_result %#x, got %#x.\n", chain_stage, ldata->get_light_result, value.get_light_result);
- ok(value.enabled == ldata->enabled,
- ok(!value.enabled == !ldata->enabled,
Is that an unrelated change? I remember us caring about the specific value GetLightEnable() returns, so the test was probably intentionally written this way.
After rearranging some tests the test started failing with exactly the same failing values under Wine and Windows, so I changed this to boolean comparison. I will investigate this and get the test back to exact values comparison, even if maybe I will have to add yet another quirk.
@@ -3641,6 +3641,7 @@ struct wined3d_saved_states { DWORD transform[(WINED3D_HIGHEST_TRANSFORM_STATE >> 5) + 1]; WORD streamSource; /* WINED3D_MAX_STREAMS, 16 */
- BOOL stream_offset_ignore; WORD streamFreq; /* WINED3D_MAX_STREAMS, 16 */
Putting a BOOL between two WORDs really isn't ideal for structure packing. Rather than just moving the BOOL though, perhaps it makes more sense to invert its meaning, take a bit out of "padding", and add a "DWORD stream_offset : 1;" instead?
store_stream_offset maybe? I suggest this as the flag does not influence state block application, only the capturing of the offset.
On Thu, 4 Apr 2019 at 19:19, Paul Gofman gofmanp@gmail.com wrote:
store_stream_offset maybe? I suggest this as the flag does not influence state block application, only the capturing of the offset.
I think that's implied by the name of the structure (wined3d_saved_states), but don't feel strongly about it.
On 4/4/19 17:58, Henri Verbeet wrote:
On Thu, 4 Apr 2019 at 19:19, Paul Gofman gofmanp@gmail.com wrote:
store_stream_offset maybe? I suggest this as the flag does not influence state block application, only the capturing of the offset.
I think that's implied by the name of the structure (wined3d_saved_states), but don't feel strongly about it.
Well, it is straighforward for the other fields: if they are stored, they will be applied; if the state is recaptured, they are updated in saved state. This one turns out to be different: it can be stored, it will be applied, but it will not be updated on the consequent recapture if the flag is set.
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=50468
Your paranoid android.
=== debian9 (build log) ===
X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig)
=== debian9 (build log) ===
X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig) X Error of failed request: BadValue (integer parameter out of range for operation) Major opcode of failed request: 140 (RANDR) Minor opcode of failed request: 21 (RRSetCrtcConfig)