1 /*
2 * This file is part of libplacebo.
3 *
4 * libplacebo is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * libplacebo is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "gpu.h"
19 #include "formats.h"
20
tex_subresource(pl_tex tex)21 static inline UINT tex_subresource(pl_tex tex)
22 {
23 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
24 return tex_p->array_slice >= 0 ? tex_p->array_slice : 0;
25 }
26
tex_init(pl_gpu gpu,pl_tex tex)27 static bool tex_init(pl_gpu gpu, pl_tex tex)
28 {
29 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
30 struct d3d11_ctx *ctx = p->ctx;
31 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
32
33 if (tex->params.sampleable || tex->params.storable) {
34 // The SRV format may be omitted when it matches the texture format, but
35 // for simplicity's sake we always set it. It will match the texture
36 // format for textures created with tex_create, but it can be different
37 // for video textures wrapped with pl_d3d11_wrap.
38 D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc = {
39 .Format = fmt_to_dxgi(tex->params.format),
40 };
41 switch (pl_tex_params_dimension(tex->params)) {
42 case 1:
43 if (tex_p->array_slice >= 0) {
44 srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1DARRAY;
45 srvdesc.Texture1DArray.MipLevels = 1;
46 srvdesc.Texture1DArray.FirstArraySlice = tex_p->array_slice;
47 srvdesc.Texture1DArray.ArraySize = 1;
48 } else {
49 srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE1D;
50 srvdesc.Texture1D.MipLevels = 1;
51 }
52 break;
53 case 2:
54 if (tex_p->array_slice >= 0) {
55 srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY;
56 srvdesc.Texture2DArray.MipLevels = 1;
57 srvdesc.Texture2DArray.FirstArraySlice = tex_p->array_slice;
58 srvdesc.Texture2DArray.ArraySize = 1;
59 } else {
60 srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
61 srvdesc.Texture2D.MipLevels = 1;
62 }
63 break;
64 case 3:
65 // D3D11 does not have Texture3D arrays
66 srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE3D;
67 srvdesc.Texture3D.MipLevels = 1;
68 break;
69 }
70 D3D(ID3D11Device_CreateShaderResourceView(p->dev, tex_p->res, &srvdesc,
71 &tex_p->srv));
72 }
73
74 if (tex->params.renderable) {
75 D3D(ID3D11Device_CreateRenderTargetView(p->dev, tex_p->res, NULL,
76 &tex_p->rtv));
77 }
78
79 if (p->fl >= D3D_FEATURE_LEVEL_11_0 && tex->params.storable) {
80 D3D(ID3D11Device_CreateUnorderedAccessView(p->dev, tex_p->res, NULL,
81 &tex_p->uav));
82 }
83
84 return true;
85 error:
86 return false;
87 }
88
pl_d3d11_tex_destroy(pl_gpu gpu,pl_tex tex)89 void pl_d3d11_tex_destroy(pl_gpu gpu, pl_tex tex)
90 {
91 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
92 struct d3d11_ctx *ctx = p->ctx;
93 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
94
95 SAFE_RELEASE(tex_p->srv);
96 SAFE_RELEASE(tex_p->rtv);
97 SAFE_RELEASE(tex_p->uav);
98 SAFE_RELEASE(tex_p->res);
99 SAFE_RELEASE(tex_p->staging);
100
101 pl_d3d11_flush_message_queue(ctx, "After texture destroy");
102
103 pl_free((void *) tex);
104 }
105
pl_d3d11_tex_create(pl_gpu gpu,const struct pl_tex_params * params)106 pl_tex pl_d3d11_tex_create(pl_gpu gpu, const struct pl_tex_params *params)
107 {
108 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
109 struct d3d11_ctx *ctx = p->ctx;
110
111 struct pl_tex *tex = pl_zalloc_obj(NULL, tex, struct pl_tex_d3d11);
112 tex->params = *params;
113 tex->params.initial_data = NULL;
114 tex->sampler_type = PL_SAMPLER_NORMAL;
115
116 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
117
118 DXGI_FORMAT dxfmt = fmt_to_dxgi(params->format);
119
120 D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
121 D3D11_BIND_FLAG bind_flags = 0;
122
123 if (p->fl >= D3D_FEATURE_LEVEL_11_0) {
124 // On >=FL11_0, blit emulation needs image storage
125 tex->params.storable |= params->blit_src || params->blit_dst;
126
127 // Blit emulation can use a sampler for linear filtering during stretch
128 if ((tex->params.format->caps & PL_FMT_CAP_LINEAR) && params->blit_src)
129 tex->params.sampleable = true;
130 } else {
131 // On <FL11_0, blit emulation uses a render pass
132 tex->params.sampleable |= params->blit_src;
133 tex->params.renderable |= params->blit_dst;
134 }
135
136 if (tex->params.sampleable)
137 bind_flags |= D3D11_BIND_SHADER_RESOURCE;
138 if (tex->params.renderable)
139 bind_flags |= D3D11_BIND_RENDER_TARGET;
140 if (p->fl >= D3D_FEATURE_LEVEL_11_0 && tex->params.storable)
141 bind_flags |= D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
142
143 // Apparently IMMUTABLE textures are efficient, so try to infer whether we
144 // can use one
145 if (params->initial_data && !tex->params.renderable &&
146 !tex->params.storable && !params->host_writable)
147 usage = D3D11_USAGE_IMMUTABLE;
148
149 // In FL9_x, resources with only D3D11_BIND_SHADER_RESOURCE can't be copied
150 // from GPU-accessible memory to CPU-accessible memory. The only other bind
151 // flag we set on this FL is D3D11_BIND_RENDER_TARGET, so set it.
152 if (p->fl <= D3D_FEATURE_LEVEL_9_3 && tex->params.host_readable)
153 bind_flags |= D3D11_BIND_RENDER_TARGET;
154
155 // In FL9_x, when using DEFAULT or IMMUTABLE, BindFlags cannot be zero
156 if (p->fl <= D3D_FEATURE_LEVEL_9_3 && !bind_flags)
157 bind_flags |= D3D11_BIND_SHADER_RESOURCE;
158
159 D3D11_SUBRESOURCE_DATA data;
160 D3D11_SUBRESOURCE_DATA *pdata = NULL;
161 if (params->initial_data) {
162 data = (D3D11_SUBRESOURCE_DATA) {
163 .pSysMem = params->initial_data,
164 .SysMemPitch = params->w * params->format->texel_size,
165 };
166 if (params->d)
167 data.SysMemSlicePitch = data.SysMemPitch * params->h;
168 pdata = &data;
169 }
170
171 switch (pl_tex_params_dimension(*params)) {
172 case 1:;
173 D3D11_TEXTURE1D_DESC desc1d = {
174 .Width = params->w,
175 .MipLevels = 1,
176 .ArraySize = 1,
177 .Format = dxfmt,
178 .Usage = usage,
179 .BindFlags = bind_flags,
180 };
181 D3D(ID3D11Device_CreateTexture1D(p->dev, &desc1d, pdata, &tex_p->tex1d));
182 tex_p->res = (ID3D11Resource *)tex_p->tex1d;
183
184 // Create a staging texture with CPU access for pl_tex_download()
185 if (params->host_readable) {
186 desc1d.BindFlags = 0;
187 desc1d.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
188 desc1d.Usage = D3D11_USAGE_STAGING;
189
190 D3D(ID3D11Device_CreateTexture1D(p->dev, &desc1d, NULL,
191 &tex_p->staging1d));
192 tex_p->staging = (ID3D11Resource *) tex_p->staging1d;
193 }
194 break;
195 case 2:;
196 D3D11_TEXTURE2D_DESC desc2d = {
197 .Width = params->w,
198 .Height = params->h,
199 .MipLevels = 1,
200 .ArraySize = 1,
201 .SampleDesc.Count = 1,
202 .Format = dxfmt,
203 .Usage = usage,
204 .BindFlags = bind_flags,
205 };
206 D3D(ID3D11Device_CreateTexture2D(p->dev, &desc2d, pdata, &tex_p->tex2d));
207 tex_p->res = (ID3D11Resource *)tex_p->tex2d;
208
209 // Create a staging texture with CPU access for pl_tex_download()
210 if (params->host_readable) {
211 desc2d.BindFlags = 0;
212 desc2d.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
213 desc2d.Usage = D3D11_USAGE_STAGING;
214
215 D3D(ID3D11Device_CreateTexture2D(p->dev, &desc2d, NULL,
216 &tex_p->staging2d));
217 tex_p->staging = (ID3D11Resource *) tex_p->staging2d;
218 }
219 break;
220 case 3:;
221 D3D11_TEXTURE3D_DESC desc3d = {
222 .Width = params->w,
223 .Height = params->h,
224 .Depth = params->d,
225 .MipLevels = 1,
226 .Format = dxfmt,
227 .Usage = usage,
228 .BindFlags = bind_flags,
229 };
230 D3D(ID3D11Device_CreateTexture3D(p->dev, &desc3d, pdata, &tex_p->tex3d));
231 tex_p->res = (ID3D11Resource *)tex_p->tex3d;
232
233 // Create a staging texture with CPU access for pl_tex_download()
234 if (params->host_readable) {
235 desc3d.BindFlags = 0;
236 desc3d.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
237 desc3d.Usage = D3D11_USAGE_STAGING;
238
239 D3D(ID3D11Device_CreateTexture3D(p->dev, &desc3d, NULL,
240 &tex_p->staging3d));
241 tex_p->staging = (ID3D11Resource *) tex_p->staging3d;
242 }
243 break;
244 default:
245 pl_unreachable();
246 }
247
248 tex_p->array_slice = -1;
249
250 if (!tex_init(gpu, tex))
251 goto error;
252
253 pl_d3d11_flush_message_queue(ctx, "After texture create");
254
255 return tex;
256
257 error:
258 pl_d3d11_tex_destroy(gpu, tex);
259 return NULL;
260 }
261
pl_d3d11_wrap(pl_gpu gpu,const struct pl_d3d11_wrap_params * params)262 pl_tex pl_d3d11_wrap(pl_gpu gpu, const struct pl_d3d11_wrap_params *params)
263 {
264 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
265 struct d3d11_ctx *ctx = p->ctx;
266
267 struct pl_tex *tex = pl_zalloc_obj(NULL, tex, struct pl_tex_d3d11);
268 tex->sampler_type = PL_SAMPLER_NORMAL;
269
270 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
271
272 DXGI_FORMAT fmt = DXGI_FORMAT_UNKNOWN;
273 D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
274 D3D11_BIND_FLAG bind_flags = 0;
275 UINT mip_levels = 1;
276 UINT array_size = 1;
277 UINT sample_count = 1;
278
279 D3D11_RESOURCE_DIMENSION type;
280 ID3D11Resource_GetType(params->tex, &type);
281
282 switch (type) {
283 case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
284 D3D(ID3D11Resource_QueryInterface(params->tex, &IID_ID3D11Texture1D,
285 (void **) &tex_p->tex1d));
286 tex_p->res = (ID3D11Resource *) tex_p->tex1d;
287
288 D3D11_TEXTURE1D_DESC desc1d;
289 ID3D11Texture1D_GetDesc(tex_p->tex1d, &desc1d);
290
291 tex->params.w = desc1d.Width;
292 mip_levels = desc1d.MipLevels;
293 array_size = desc1d.ArraySize;
294 fmt = desc1d.Format;
295 usage = desc1d.Usage;
296 bind_flags = desc1d.BindFlags;
297 break;
298
299 case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
300 D3D(ID3D11Resource_QueryInterface(params->tex, &IID_ID3D11Texture2D,
301 (void **) &tex_p->tex2d));
302 tex_p->res = (ID3D11Resource *) tex_p->tex2d;
303
304 D3D11_TEXTURE2D_DESC desc2d;
305 ID3D11Texture2D_GetDesc(tex_p->tex2d, &desc2d);
306
307 tex->params.w = desc2d.Width;
308 tex->params.h = desc2d.Height;
309 mip_levels = desc2d.MipLevels;
310 array_size = desc2d.ArraySize;
311 fmt = desc2d.Format;
312 sample_count = desc2d.SampleDesc.Count;
313 usage = desc2d.Usage;
314 bind_flags = desc2d.BindFlags;
315
316 // Allow the format and size of 2D textures to be overridden to support
317 // shader views of video resources
318 if (params->fmt) {
319 fmt = params->fmt;
320 tex->params.w = params->w;
321 tex->params.h = params->h;
322 }
323
324 break;
325
326 case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
327 D3D(ID3D11Resource_QueryInterface(params->tex, &IID_ID3D11Texture3D,
328 (void **) &tex_p->tex3d));
329 tex_p->res = (ID3D11Resource *) tex_p->tex3d;
330
331 D3D11_TEXTURE3D_DESC desc3d;
332 ID3D11Texture3D_GetDesc(tex_p->tex3d, &desc3d);
333
334 tex->params.w = desc3d.Width;
335 tex->params.h = desc3d.Height;
336 tex->params.d = desc3d.Depth;
337 mip_levels = desc3d.MipLevels;
338 fmt = desc3d.Format;
339 usage = desc3d.Usage;
340 bind_flags = desc3d.BindFlags;
341 break;
342
343 case D3D11_RESOURCE_DIMENSION_UNKNOWN:
344 case D3D11_RESOURCE_DIMENSION_BUFFER:
345 PL_ERR(gpu, "Resource is not suitable to wrap");
346 goto error;
347 }
348
349 if (mip_levels != 1) {
350 PL_ERR(gpu, "Mipmapped textures not supported for wrapping");
351 goto error;
352 }
353 if (sample_count != 1) {
354 PL_ERR(gpu, "Multisampled textures not supported for wrapping");
355 goto error;
356 }
357 if (usage != D3D11_USAGE_DEFAULT) {
358 PL_ERR(gpu, "Resource is not D3D11_USAGE_DEFAULT");
359 goto error;
360 }
361
362 if (array_size > 1) {
363 if (params->array_slice < 0 || params->array_slice >= array_size) {
364 PL_ERR(gpu, "array_slice out of range");
365 goto error;
366 }
367 tex_p->array_slice = params->array_slice;
368 } else {
369 tex_p->array_slice = -1;
370 }
371
372 if (bind_flags & D3D11_BIND_SHADER_RESOURCE) {
373 tex->params.sampleable = true;
374
375 // Blit emulation uses a render pass on <FL11_0
376 if (p->fl < D3D_FEATURE_LEVEL_11_0)
377 tex->params.blit_src = true;
378 }
379 if (bind_flags & D3D11_BIND_RENDER_TARGET) {
380 tex->params.renderable = true;
381
382 // Blit emulation uses a render pass on <FL11_0
383 if (p->fl < D3D_FEATURE_LEVEL_11_0)
384 tex->params.blit_dst = true;
385 }
386 static const D3D11_BIND_FLAG storable_flags =
387 D3D11_BIND_UNORDERED_ACCESS | D3D11_BIND_SHADER_RESOURCE;
388 if ((bind_flags & storable_flags) == storable_flags) {
389 tex->params.storable = true;
390
391 // Blit emulation uses image storage on >=FL11_0. A feature level check
392 // isn't required because <FL11_0 doesn't have storable images.
393 tex->params.blit_src = tex->params.blit_dst = true;
394 }
395
396 for (int i = 0; i < gpu->num_formats; i++) {
397 DXGI_FORMAT target_fmt = fmt_to_dxgi(gpu->formats[i]);
398 if (fmt == target_fmt) {
399 tex->params.format = gpu->formats[i];
400 break;
401 }
402 }
403 if (!tex->params.format) {
404 PL_ERR(gpu, "Could not find a suitable pl_fmt for wrapped resource");
405 goto error;
406 }
407
408 if (!tex_init(gpu, tex))
409 goto error;
410
411 pl_d3d11_flush_message_queue(ctx, "After texture wrap");
412
413 return tex;
414
415 error:
416 pl_d3d11_tex_destroy(gpu, tex);
417 return NULL;
418 }
419
pl_d3d11_tex_invalidate(pl_gpu gpu,pl_tex tex)420 void pl_d3d11_tex_invalidate(pl_gpu gpu, pl_tex tex)
421 {
422 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
423 struct d3d11_ctx *ctx = p->ctx;
424 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
425
426 // Resource discarding requires D3D11.1
427 if (!p->imm1)
428 return;
429
430 // Prefer discarding a view to discarding the whole resource. The reason
431 // for this is that a pl_tex can refer to a single member of a texture
432 // array. Discarding the SRV, RTV or UAV should only discard that member.
433 if (tex_p->rtv) {
434 ID3D11DeviceContext1_DiscardView(p->imm1, (ID3D11View *) tex_p->rtv);
435 } else if (tex_p->uav) {
436 ID3D11DeviceContext1_DiscardView(p->imm1, (ID3D11View *) tex_p->uav);
437 } else if (tex_p->srv) {
438 ID3D11DeviceContext1_DiscardView(p->imm1, (ID3D11View *) tex_p->srv);
439 } else if (tex_p->array_slice < 0) {
440 // If there are no views, only discard if the ID3D11Resource is not a
441 // texture array
442 ID3D11DeviceContext1_DiscardResource(p->imm1, tex_p->res);
443 }
444
445 pl_d3d11_flush_message_queue(ctx, "After texture invalidate");
446 }
447
pl_d3d11_tex_clear_ex(pl_gpu gpu,pl_tex tex,const union pl_clear_color color)448 void pl_d3d11_tex_clear_ex(pl_gpu gpu, pl_tex tex,
449 const union pl_clear_color color)
450 {
451 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
452 struct d3d11_ctx *ctx = p->ctx;
453 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
454
455 if (tex->params.format->type == PL_FMT_UINT) {
456 if (tex_p->uav) {
457 ID3D11DeviceContext_ClearUnorderedAccessViewUint(p->imm, tex_p->uav,
458 color.u);
459 } else {
460 float c[4] = { color.u[0], color.u[1], color.u[2], color.u[3] };
461 ID3D11DeviceContext_ClearRenderTargetView(p->imm, tex_p->rtv, c);
462 }
463
464 } else if (tex->params.format->type == PL_FMT_SINT) {
465 if (tex_p->uav) {
466 ID3D11DeviceContext_ClearUnorderedAccessViewUint(p->imm, tex_p->uav,
467 color.i);
468 } else {
469 float c[4] = { color.i[0], color.i[1], color.i[2], color.i[3] };
470 ID3D11DeviceContext_ClearRenderTargetView(p->imm, tex_p->rtv, c);
471 }
472
473 } else if (tex_p->rtv) {
474 ID3D11DeviceContext_ClearRenderTargetView(p->imm, tex_p->rtv, color.f);
475 } else {
476 ID3D11DeviceContext_ClearUnorderedAccessViewFloat(p->imm, tex_p->uav, color.f);
477 }
478
479 pl_d3d11_flush_message_queue(ctx, "After texture clear");
480 }
481
482 #define pl_rect3d_to_box(rc) \
483 ((D3D11_BOX) { \
484 .left = rc.x0, .top = rc.y0, .front = rc.z0, \
485 .right = rc.x1, .bottom = rc.y1, .back = rc.z1, \
486 })
487
pl_d3d11_tex_blit(pl_gpu gpu,const struct pl_tex_blit_params * params)488 void pl_d3d11_tex_blit(pl_gpu gpu, const struct pl_tex_blit_params *params)
489 {
490 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
491 struct d3d11_ctx *ctx = p->ctx;
492 struct pl_tex_d3d11 *src_p = PL_PRIV(params->src);
493 DXGI_FORMAT src_fmt = fmt_to_dxgi(params->src->params.format);
494 struct pl_tex_d3d11 *dst_p = PL_PRIV(params->dst);
495 DXGI_FORMAT dst_fmt = fmt_to_dxgi(params->dst->params.format);
496
497 // If the blit operation doesn't require flipping, scaling or format
498 // conversion, we can use CopySubresourceRegion
499 struct pl_rect3d src_rc = params->src_rc, dst_rc = params->dst_rc;
500 if (pl_rect3d_eq(src_rc, dst_rc) && src_fmt == dst_fmt) {
501 struct pl_rect3d rc = params->src_rc;
502 pl_rect3d_normalize(&rc);
503
504 ID3D11DeviceContext_CopySubresourceRegion(p->imm, dst_p->res,
505 tex_subresource(params->dst), rc.x0, rc.y0, rc.z0, src_p->res,
506 tex_subresource(params->src), &pl_rect3d_to_box(rc));
507 } else if (p->fl >= D3D_FEATURE_LEVEL_11_0) {
508 if (!pl_tex_blit_compute(gpu, p->dp, params))
509 PL_ERR(gpu, "Failed compute shader fallback blit");
510 } else {
511 pl_tex_blit_raster(gpu, p->dp, params);
512 }
513
514 pl_d3d11_flush_message_queue(ctx, "After texture blit");
515 }
516
pl_d3d11_tex_upload(pl_gpu gpu,const struct pl_tex_transfer_params * params)517 bool pl_d3d11_tex_upload(pl_gpu gpu, const struct pl_tex_transfer_params *params)
518 {
519 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
520 struct d3d11_ctx *ctx = p->ctx;
521 pl_tex tex = params->tex;
522 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
523
524 UINT row_pitch = params->stride_w * tex->params.format->texel_size;
525 UINT depth_pitch = row_pitch * params->stride_h;
526
527 pl_d3d11_timer_start(gpu, params->timer);
528
529 ID3D11DeviceContext_UpdateSubresource(p->imm, tex_p->res,
530 tex_subresource(tex), &pl_rect3d_to_box(params->rc), params->ptr,
531 row_pitch, depth_pitch);
532
533 pl_d3d11_timer_end(gpu, params->timer);
534 pl_d3d11_flush_message_queue(ctx, "After texture upload");
535
536 return true;
537 }
538
pl_d3d11_tex_download(pl_gpu gpu,const struct pl_tex_transfer_params * params)539 bool pl_d3d11_tex_download(pl_gpu gpu, const struct pl_tex_transfer_params *params)
540 {
541 struct pl_gpu_d3d11 *p = PL_PRIV(gpu);
542 struct d3d11_ctx *ctx = p->ctx;
543 const struct pl_tex *tex = params->tex;
544 struct pl_tex_d3d11 *tex_p = PL_PRIV(tex);
545
546 if (!tex_p->staging)
547 return false;
548
549 pl_d3d11_timer_start(gpu, params->timer);
550
551 ID3D11DeviceContext_CopySubresourceRegion(p->imm,
552 (ID3D11Resource *) tex_p->staging, 0, params->rc.x0, params->rc.y0,
553 params->rc.z0, tex_p->res, tex_subresource(tex),
554 &pl_rect3d_to_box(params->rc));
555
556 UINT row_pitch = params->stride_w * tex->params.format->texel_size;
557 UINT depth_pitch = row_pitch * params->stride_h;
558
559 D3D11_MAPPED_SUBRESOURCE lock;
560 D3D(ID3D11DeviceContext_Map(p->imm, (ID3D11Resource *) tex_p->staging, 0,
561 D3D11_MAP_READ, 0, &lock));
562
563 char *cdst = params->ptr;
564 char *csrc = lock.pData;
565 size_t line_size = pl_rect_w(params->rc) * tex->params.format->texel_size;
566 for (int z = 0; z < pl_rect_d(params->rc); z++) {
567 for (int y = 0; y < pl_rect_h(params->rc); y++) {
568 memcpy(cdst + z * depth_pitch + y * row_pitch,
569 csrc + (params->rc.z0 + z) * lock.DepthPitch +
570 (params->rc.y0 + y) * lock.RowPitch + params->rc.x0,
571 line_size);
572 }
573 }
574
575 ID3D11DeviceContext_Unmap(p->imm, (ID3D11Resource*)tex_p->staging, 0);
576
577 pl_d3d11_timer_end(gpu, params->timer);
578 pl_d3d11_flush_message_queue(ctx, "After texture download");
579
580 return true;
581
582 error:
583 return false;
584 }
585