1 //
2 // Copyright 2012 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6
7 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
8 // the actual underlying resources of a Texture
9
10 #include "libANGLE/renderer/d3d/d3d11/Image11.h"
11
12 #include "common/utilities.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Framebuffer.h"
15 #include "libANGLE/FramebufferAttachment.h"
16 #include "libANGLE/formatutils.h"
17 #include "libANGLE/renderer/d3d/d3d11/Context11.h"
18 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
19 #include "libANGLE/renderer/d3d/d3d11/Renderer11.h"
20 #include "libANGLE/renderer/d3d/d3d11/TextureStorage11.h"
21 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
22 #include "libANGLE/renderer/d3d/d3d11/renderer11_utils.h"
23 #include "libANGLE/renderer/d3d/d3d11/texture_format_table.h"
24
25 namespace rx
26 {
27
Image11(Renderer11 * renderer)28 Image11::Image11(Renderer11 *renderer)
29 : mRenderer(renderer),
30 mDXGIFormat(DXGI_FORMAT_UNKNOWN),
31 mStagingTexture(),
32 mStagingSubresource(0),
33 mRecoverFromStorage(false),
34 mAssociatedStorage(nullptr),
35 mAssociatedImageIndex(),
36 mRecoveredFromStorageCount(0)
37 {}
38
~Image11()39 Image11::~Image11()
40 {
41 disassociateStorage();
42 releaseStagingTexture();
43 }
44
45 // static
GenerateMipmap(const gl::Context * context,Image11 * dest,Image11 * src,const Renderer11DeviceCaps & rendererCaps)46 angle::Result Image11::GenerateMipmap(const gl::Context *context,
47 Image11 *dest,
48 Image11 *src,
49 const Renderer11DeviceCaps &rendererCaps)
50 {
51 ASSERT(src->getDXGIFormat() == dest->getDXGIFormat());
52 ASSERT(src->getWidth() == 1 || src->getWidth() / 2 == dest->getWidth());
53 ASSERT(src->getHeight() == 1 || src->getHeight() / 2 == dest->getHeight());
54
55 D3D11_MAPPED_SUBRESOURCE destMapped;
56 ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
57 d3d11::ScopedUnmapper<Image11> destRAII(dest);
58
59 D3D11_MAPPED_SUBRESOURCE srcMapped;
60 ANGLE_TRY(src->map(context, D3D11_MAP_READ, &srcMapped));
61 d3d11::ScopedUnmapper<Image11> srcRAII(src);
62
63 const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData);
64 uint8_t *destData = static_cast<uint8_t *>(destMapped.pData);
65
66 auto mipGenerationFunction =
67 d3d11::Format::Get(src->getInternalFormat(), rendererCaps).format().mipGenerationFunction;
68 mipGenerationFunction(src->getWidth(), src->getHeight(), src->getDepth(), sourceData,
69 srcMapped.RowPitch, srcMapped.DepthPitch, destData, destMapped.RowPitch,
70 destMapped.DepthPitch);
71
72 dest->markDirty();
73
74 return angle::Result::Continue;
75 }
76
77 // static
CopyImage(const gl::Context * context,Image11 * dest,Image11 * source,const gl::Box & sourceBox,const gl::Offset & destOffset,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const Renderer11DeviceCaps & rendererCaps)78 angle::Result Image11::CopyImage(const gl::Context *context,
79 Image11 *dest,
80 Image11 *source,
81 const gl::Box &sourceBox,
82 const gl::Offset &destOffset,
83 bool unpackFlipY,
84 bool unpackPremultiplyAlpha,
85 bool unpackUnmultiplyAlpha,
86 const Renderer11DeviceCaps &rendererCaps)
87 {
88 D3D11_MAPPED_SUBRESOURCE destMapped;
89 ANGLE_TRY(dest->map(context, D3D11_MAP_WRITE, &destMapped));
90 d3d11::ScopedUnmapper<Image11> destRAII(dest);
91
92 D3D11_MAPPED_SUBRESOURCE srcMapped;
93 ANGLE_TRY(source->map(context, D3D11_MAP_READ, &srcMapped));
94 d3d11::ScopedUnmapper<Image11> sourceRAII(source);
95
96 const auto &sourceFormat =
97 d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format();
98 GLuint sourcePixelBytes =
99 gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes;
100
101 GLenum destUnsizedFormat = gl::GetUnsizedFormat(dest->getInternalFormat());
102 const auto &destFormat = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format();
103 const auto &destFormatInfo =
104 gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat);
105 GLuint destPixelBytes = destFormatInfo.pixelBytes;
106
107 const uint8_t *sourceData = static_cast<const uint8_t *>(srcMapped.pData) +
108 sourceBox.x * sourcePixelBytes + sourceBox.y * srcMapped.RowPitch +
109 sourceBox.z * srcMapped.DepthPitch;
110 uint8_t *destData = static_cast<uint8_t *>(destMapped.pData) + destOffset.x * destPixelBytes +
111 destOffset.y * destMapped.RowPitch + destOffset.z * destMapped.DepthPitch;
112
113 CopyImageCHROMIUM(sourceData, srcMapped.RowPitch, sourcePixelBytes, srcMapped.DepthPitch,
114 sourceFormat.pixelReadFunction, destData, destMapped.RowPitch, destPixelBytes,
115 destMapped.DepthPitch, destFormat.pixelWriteFunction, destUnsizedFormat,
116 destFormatInfo.componentType, sourceBox.width, sourceBox.height,
117 sourceBox.depth, unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha);
118
119 dest->markDirty();
120
121 return angle::Result::Continue;
122 }
123
isDirty() const124 bool Image11::isDirty() const
125 {
126 // If mDirty is true AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be
127 // recovered from TextureStorage AND the texture doesn't require init data (i.e. a blank new
128 // texture will suffice) AND robust resource initialization is not enabled then isDirty should
129 // still return false.
130 if (mDirty && !mStagingTexture.valid() && !mRecoverFromStorage)
131 {
132 const Renderer11DeviceCaps &deviceCaps = mRenderer->getRenderer11DeviceCaps();
133 const auto &formatInfo = d3d11::Format::Get(mInternalFormat, deviceCaps);
134 if (formatInfo.dataInitializerFunction == nullptr)
135 {
136 return false;
137 }
138 }
139
140 return mDirty;
141 }
142
copyToStorage(const gl::Context * context,TextureStorage * storage,const gl::ImageIndex & index,const gl::Box & region)143 angle::Result Image11::copyToStorage(const gl::Context *context,
144 TextureStorage *storage,
145 const gl::ImageIndex &index,
146 const gl::Box ®ion)
147 {
148 TextureStorage11 *storage11 = GetAs<TextureStorage11>(storage);
149
150 // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage
151 // multiple times, then we should just keep the staging texture around to prevent the copying
152 // from impacting perf. We allow the Image11 to copy its data to/from TextureStorage once. This
153 // accounts for an app making a late call to glGenerateMipmap.
154 bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
155
156 if (attemptToReleaseStagingTexture)
157 {
158 // If another image is relying on this Storage for its data, then we must let it recover its
159 // data before we overwrite it.
160 ANGLE_TRY(storage11->releaseAssociatedImage(context, index, this));
161 }
162
163 const TextureHelper11 *stagingTexture = nullptr;
164 unsigned int stagingSubresourceIndex = 0;
165 ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
166 ANGLE_TRY(storage11->updateSubresourceLevel(context, *stagingTexture, stagingSubresourceIndex,
167 index, region));
168
169 // Once the image data has been copied into the Storage, we can release it locally.
170 if (attemptToReleaseStagingTexture)
171 {
172 storage11->associateImage(this, index);
173 releaseStagingTexture();
174 mRecoverFromStorage = true;
175 mAssociatedStorage = storage11;
176 mAssociatedImageIndex = index;
177 }
178
179 return angle::Result::Continue;
180 }
181
verifyAssociatedStorageValid(TextureStorage11 * textureStorage) const182 void Image11::verifyAssociatedStorageValid(TextureStorage11 *textureStorage) const
183 {
184 ASSERT(mAssociatedStorage == textureStorage);
185 }
186
recoverFromAssociatedStorage(const gl::Context * context)187 angle::Result Image11::recoverFromAssociatedStorage(const gl::Context *context)
188 {
189 if (mRecoverFromStorage)
190 {
191 ANGLE_TRY(createStagingTexture(context));
192
193 mAssociatedStorage->verifyAssociatedImageValid(mAssociatedImageIndex, this);
194
195 // CopySubResource from the Storage to the Staging texture
196 gl::Box region(0, 0, 0, mWidth, mHeight, mDepth);
197 ANGLE_TRY(mAssociatedStorage->copySubresourceLevel(
198 context, mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region));
199 mRecoveredFromStorageCount += 1;
200
201 // Reset all the recovery parameters, even if the texture storage association is broken.
202 disassociateStorage();
203 }
204
205 return angle::Result::Continue;
206 }
207
disassociateStorage()208 void Image11::disassociateStorage()
209 {
210 if (mRecoverFromStorage)
211 {
212 // Make the texturestorage release the Image11 too
213 mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
214
215 mRecoverFromStorage = false;
216 mAssociatedStorage = nullptr;
217 mAssociatedImageIndex = gl::ImageIndex();
218 }
219 }
220
redefine(gl::TextureType type,GLenum internalformat,const gl::Extents & size,bool forceRelease)221 bool Image11::redefine(gl::TextureType type,
222 GLenum internalformat,
223 const gl::Extents &size,
224 bool forceRelease)
225 {
226 if (mWidth != size.width || mHeight != size.height || mInternalFormat != internalformat ||
227 forceRelease)
228 {
229 // End the association with the TextureStorage, since that data will be out of date.
230 // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
231 disassociateStorage();
232 mRecoveredFromStorageCount = 0;
233
234 mWidth = size.width;
235 mHeight = size.height;
236 mDepth = size.depth;
237 mInternalFormat = internalformat;
238 mType = type;
239
240 // compute the d3d format that will be used
241 const d3d11::Format &formatInfo =
242 d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps());
243 mDXGIFormat = formatInfo.texFormat;
244 mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
245
246 releaseStagingTexture();
247 mDirty = (formatInfo.dataInitializerFunction != nullptr);
248
249 return true;
250 }
251
252 return false;
253 }
254
getDXGIFormat() const255 DXGI_FORMAT Image11::getDXGIFormat() const
256 {
257 // this should only happen if the image hasn't been redefined first
258 // which would be a bug by the caller
259 ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
260
261 return mDXGIFormat;
262 }
263
264 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
265 // format/type at input
266 // into the target pixel rectangle.
loadData(const gl::Context * context,const gl::Box & area,const gl::PixelUnpackState & unpack,GLenum type,const void * input,bool applySkipImages)267 angle::Result Image11::loadData(const gl::Context *context,
268 const gl::Box &area,
269 const gl::PixelUnpackState &unpack,
270 GLenum type,
271 const void *input,
272 bool applySkipImages)
273 {
274 Context11 *context11 = GetImplAs<Context11>(context);
275
276 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
277 GLuint inputRowPitch = 0;
278 ANGLE_CHECK_GL_MATH(context11, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
279 unpack.rowLength, &inputRowPitch));
280 GLuint inputDepthPitch = 0;
281 ANGLE_CHECK_GL_MATH(context11, formatInfo.computeDepthPitch(area.height, unpack.imageHeight,
282 inputRowPitch, &inputDepthPitch));
283 GLuint inputSkipBytes = 0;
284 ANGLE_CHECK_GL_MATH(context11,
285 formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
286 applySkipImages, &inputSkipBytes));
287
288 const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
289 GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
290
291 const d3d11::Format &d3dFormatInfo =
292 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
293 LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction;
294
295 D3D11_MAPPED_SUBRESOURCE mappedImage;
296 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
297
298 uint8_t *offsetMappedData = (static_cast<uint8_t *>(mappedImage.pData) +
299 (area.y * mappedImage.RowPitch + area.x * outputPixelSize +
300 area.z * mappedImage.DepthPitch));
301 loadFunction(area.width, area.height, area.depth,
302 static_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
303 inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
304
305 unmap();
306
307 return angle::Result::Continue;
308 }
309
loadCompressedData(const gl::Context * context,const gl::Box & area,const void * input)310 angle::Result Image11::loadCompressedData(const gl::Context *context,
311 const gl::Box &area,
312 const void *input)
313 {
314 Context11 *context11 = GetImplAs<Context11>(context);
315
316 const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
317 GLuint inputRowPitch = 0;
318 ANGLE_CHECK_GL_MATH(
319 context11, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
320 GLuint inputDepthPitch = 0;
321 ANGLE_CHECK_GL_MATH(
322 context11, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
323
324 const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
325 GLuint outputPixelSize = dxgiFormatInfo.pixelBytes;
326 GLuint outputBlockWidth = dxgiFormatInfo.blockWidth;
327 GLuint outputBlockHeight = dxgiFormatInfo.blockHeight;
328
329 ASSERT(area.x % outputBlockWidth == 0);
330 ASSERT(area.y % outputBlockHeight == 0);
331
332 const d3d11::Format &d3dFormatInfo =
333 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
334 LoadImageFunction loadFunction =
335 d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction;
336
337 D3D11_MAPPED_SUBRESOURCE mappedImage;
338 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
339
340 uint8_t *offsetMappedData =
341 static_cast<uint8_t *>(mappedImage.pData) +
342 ((area.y / outputBlockHeight) * mappedImage.RowPitch +
343 (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch);
344
345 loadFunction(area.width, area.height, area.depth, static_cast<const uint8_t *>(input),
346 inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch,
347 mappedImage.DepthPitch);
348
349 unmap();
350
351 return angle::Result::Continue;
352 }
353
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)354 angle::Result Image11::copyFromTexStorage(const gl::Context *context,
355 const gl::ImageIndex &imageIndex,
356 TextureStorage *source)
357 {
358 TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
359
360 const TextureHelper11 *textureHelper = nullptr;
361 ANGLE_TRY(storage11->getResource(context, &textureHelper));
362
363 UINT subresourceIndex = 0;
364 ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex));
365
366 gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
367 return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper,
368 subresourceIndex);
369 }
370
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * sourceFBO)371 angle::Result Image11::copyFromFramebuffer(const gl::Context *context,
372 const gl::Offset &destOffset,
373 const gl::Rectangle &sourceArea,
374 const gl::Framebuffer *sourceFBO)
375 {
376 const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorAttachment();
377 ASSERT(srcAttachment);
378
379 GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat;
380 const auto &d3d11Format =
381 d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps());
382
383 if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat)
384 {
385 RenderTarget11 *rt11 = nullptr;
386 ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &rt11));
387 ASSERT(rt11->getTexture().get());
388
389 TextureHelper11 textureHelper = rt11->getTexture();
390 unsigned int sourceSubResource = rt11->getSubresourceIndex();
391
392 gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
393 return copyWithoutConversion(context, destOffset, sourceBox, textureHelper,
394 sourceSubResource);
395 }
396
397 // This format requires conversion, so we must copy the texture to staging and manually convert
398 // via readPixels
399 D3D11_MAPPED_SUBRESOURCE mappedImage;
400 ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
401
402 // determine the offset coordinate into the destination buffer
403 const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
404 GLsizei rowOffset = dxgiFormatInfo.pixelBytes * destOffset.x;
405
406 uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
407 mappedImage.RowPitch * destOffset.y + rowOffset +
408 destOffset.z * mappedImage.DepthPitch;
409
410 const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
411 const auto &destD3D11Format =
412 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
413
414 auto loadFunction = destD3D11Format.getLoadFunctions()(destFormatInfo.type);
415 angle::Result result = angle::Result::Continue;
416 if (loadFunction.requiresConversion)
417 {
418 size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
419 angle::MemoryBuffer *memoryBuffer = nullptr;
420 result = mRenderer->getScratchMemoryBuffer(GetImplAs<Context11>(context), bufferSize,
421 &memoryBuffer);
422
423 if (result == angle::Result::Continue)
424 {
425 GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
426
427 result = mRenderer->readFromAttachment(
428 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
429 memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data());
430
431 loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(),
432 memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch,
433 mappedImage.DepthPitch);
434 }
435 }
436 else
437 {
438 result = mRenderer->readFromAttachment(
439 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
440 mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
441 }
442
443 unmap();
444 mDirty = true;
445
446 return result;
447 }
448
copyWithoutConversion(const gl::Context * context,const gl::Offset & destOffset,const gl::Box & sourceArea,const TextureHelper11 & textureHelper,UINT sourceSubResource)449 angle::Result Image11::copyWithoutConversion(const gl::Context *context,
450 const gl::Offset &destOffset,
451 const gl::Box &sourceArea,
452 const TextureHelper11 &textureHelper,
453 UINT sourceSubResource)
454 {
455 // No conversion needed-- use copyback fastpath
456 const TextureHelper11 *stagingTexture = nullptr;
457 unsigned int stagingSubresourceIndex = 0;
458 ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
459
460 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
461
462 const gl::Extents &extents = textureHelper.getExtents();
463
464 D3D11_BOX srcBox;
465 srcBox.left = sourceArea.x;
466 srcBox.right = sourceArea.x + sourceArea.width;
467 srcBox.top = sourceArea.y;
468 srcBox.bottom = sourceArea.y + sourceArea.height;
469 srcBox.front = sourceArea.z;
470 srcBox.back = sourceArea.z + sourceArea.depth;
471
472 if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
473 {
474 D3D11_TEXTURE2D_DESC resolveDesc;
475 resolveDesc.Width = extents.width;
476 resolveDesc.Height = extents.height;
477 resolveDesc.MipLevels = 1;
478 resolveDesc.ArraySize = 1;
479 resolveDesc.Format = textureHelper.getFormat();
480 resolveDesc.SampleDesc.Count = 1;
481 resolveDesc.SampleDesc.Quality = 0;
482 resolveDesc.Usage = D3D11_USAGE_DEFAULT;
483 resolveDesc.BindFlags = 0;
484 resolveDesc.CPUAccessFlags = 0;
485 resolveDesc.MiscFlags = 0;
486
487 d3d11::Texture2D resolveTex;
488 ANGLE_TRY(
489 mRenderer->allocateResource(GetImplAs<Context11>(context), resolveDesc, &resolveTex));
490
491 deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(),
492 sourceSubResource, textureHelper.getFormat());
493
494 deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
495 destOffset.x, destOffset.y, destOffset.z,
496 resolveTex.get(), 0, &srcBox);
497 }
498 else
499 {
500 deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
501 destOffset.x, destOffset.y, destOffset.z,
502 textureHelper.get(), sourceSubResource, &srcBox);
503 }
504
505 mDirty = true;
506 return angle::Result::Continue;
507 }
508
getStagingTexture(const gl::Context * context,const TextureHelper11 ** outStagingTexture,unsigned int * outSubresourceIndex)509 angle::Result Image11::getStagingTexture(const gl::Context *context,
510 const TextureHelper11 **outStagingTexture,
511 unsigned int *outSubresourceIndex)
512 {
513 ANGLE_TRY(createStagingTexture(context));
514
515 *outStagingTexture = &mStagingTexture;
516 *outSubresourceIndex = mStagingSubresource;
517 return angle::Result::Continue;
518 }
519
releaseStagingTexture()520 void Image11::releaseStagingTexture()
521 {
522 mStagingTexture.reset();
523 mStagingTextureSubresourceVerifier.reset();
524 }
525
createStagingTexture(const gl::Context * context)526 angle::Result Image11::createStagingTexture(const gl::Context *context)
527 {
528 if (mStagingTexture.valid())
529 {
530 return angle::Result::Continue;
531 }
532
533 ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0);
534
535 const DXGI_FORMAT dxgiFormat = getDXGIFormat();
536 const auto &formatInfo =
537 d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
538
539 int lodOffset = 1;
540 GLsizei width = mWidth;
541 GLsizei height = mHeight;
542
543 // adjust size if needed for compressed textures
544 d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
545
546 Context11 *context11 = GetImplAs<Context11>(context);
547
548 switch (mType)
549 {
550 case gl::TextureType::_3D:
551 {
552 D3D11_TEXTURE3D_DESC desc;
553 desc.Width = width;
554 desc.Height = height;
555 desc.Depth = mDepth;
556 desc.MipLevels = lodOffset + 1;
557 desc.Format = dxgiFormat;
558 desc.Usage = D3D11_USAGE_STAGING;
559 desc.BindFlags = 0;
560 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
561 desc.MiscFlags = 0;
562
563 if (formatInfo.dataInitializerFunction != nullptr)
564 {
565 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
566 ANGLE_TRY(d3d11::GenerateInitialTextureData(
567 context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
568 mDepth, lodOffset + 1, &initialData));
569
570 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
571 initialData.data(), &mStagingTexture));
572 }
573 else
574 {
575 ANGLE_TRY(
576 mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
577 }
578
579 mStagingTexture.setDebugName("Image11::StagingTexture3D");
580 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
581 mStagingTextureSubresourceVerifier.setDesc(desc);
582 }
583 break;
584
585 case gl::TextureType::_2D:
586 case gl::TextureType::_2DArray:
587 case gl::TextureType::CubeMap:
588 {
589 D3D11_TEXTURE2D_DESC desc;
590 desc.Width = width;
591 desc.Height = height;
592 desc.MipLevels = lodOffset + 1;
593 desc.ArraySize = 1;
594 desc.Format = dxgiFormat;
595 desc.SampleDesc.Count = 1;
596 desc.SampleDesc.Quality = 0;
597 desc.Usage = D3D11_USAGE_STAGING;
598 desc.BindFlags = 0;
599 desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
600 desc.MiscFlags = 0;
601
602 if (formatInfo.dataInitializerFunction != nullptr)
603 {
604 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
605 ANGLE_TRY(d3d11::GenerateInitialTextureData(
606 context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
607 1, lodOffset + 1, &initialData));
608
609 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
610 initialData.data(), &mStagingTexture));
611 }
612 else
613 {
614 ANGLE_TRY(
615 mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
616 }
617
618 mStagingTexture.setDebugName("Image11::StagingTexture2D");
619 mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
620 mStagingTextureSubresourceVerifier.setDesc(desc);
621 }
622 break;
623
624 default:
625 UNREACHABLE();
626 }
627
628 mDirty = false;
629 return angle::Result::Continue;
630 }
631
map(const gl::Context * context,D3D11_MAP mapType,D3D11_MAPPED_SUBRESOURCE * map)632 angle::Result Image11::map(const gl::Context *context,
633 D3D11_MAP mapType,
634 D3D11_MAPPED_SUBRESOURCE *map)
635 {
636 // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
637 ANGLE_TRY(recoverFromAssociatedStorage(context));
638
639 const TextureHelper11 *stagingTexture = nullptr;
640 unsigned int subresourceIndex = 0;
641 ANGLE_TRY(getStagingTexture(context, &stagingTexture, &subresourceIndex));
642
643 ASSERT(stagingTexture && stagingTexture->valid());
644
645 ANGLE_TRY(
646 mRenderer->mapResource(context, stagingTexture->get(), subresourceIndex, mapType, 0, map));
647
648 if (!mStagingTextureSubresourceVerifier.wrap(mapType, map))
649 {
650 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
651 deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
652 Context11 *context11 = GetImplAs<Context11>(context);
653 context11->handleError(GL_OUT_OF_MEMORY,
654 "Failed to allocate staging texture mapping verifier buffer.",
655 __FILE__, ANGLE_FUNCTION, __LINE__);
656 return angle::Result::Stop;
657 }
658
659 mDirty = true;
660
661 return angle::Result::Continue;
662 }
663
unmap()664 void Image11::unmap()
665 {
666 if (mStagingTexture.valid())
667 {
668 mStagingTextureSubresourceVerifier.unwrap();
669 ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
670 deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
671 }
672 }
673
674 } // namespace rx
675