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 &region)
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         markDirty();
205     }
206 
207     return angle::Result::Continue;
208 }
209 
disassociateStorage()210 void Image11::disassociateStorage()
211 {
212     if (mRecoverFromStorage)
213     {
214         // Make the texturestorage release the Image11 too
215         mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
216 
217         mRecoverFromStorage   = false;
218         mAssociatedStorage    = nullptr;
219         mAssociatedImageIndex = gl::ImageIndex();
220     }
221 }
222 
redefine(gl::TextureType type,GLenum internalformat,const gl::Extents & size,bool forceRelease)223 bool Image11::redefine(gl::TextureType type,
224                        GLenum internalformat,
225                        const gl::Extents &size,
226                        bool forceRelease)
227 {
228     if (mWidth != size.width || mHeight != size.height || mDepth != size.depth ||
229         mInternalFormat != internalformat || forceRelease)
230     {
231         // End the association with the TextureStorage, since that data will be out of date.
232         // Also reset mRecoveredFromStorageCount since this Image is getting completely redefined.
233         disassociateStorage();
234         mRecoveredFromStorageCount = 0;
235 
236         mWidth          = size.width;
237         mHeight         = size.height;
238         mDepth          = size.depth;
239         mInternalFormat = internalformat;
240         mType           = type;
241 
242         // compute the d3d format that will be used
243         const d3d11::Format &formatInfo =
244             d3d11::Format::Get(internalformat, mRenderer->getRenderer11DeviceCaps());
245         mDXGIFormat = formatInfo.texFormat;
246         mRenderable = (formatInfo.rtvFormat != DXGI_FORMAT_UNKNOWN);
247 
248         releaseStagingTexture();
249         mDirty = (formatInfo.dataInitializerFunction != nullptr);
250 
251         return true;
252     }
253 
254     return false;
255 }
256 
getDXGIFormat() const257 DXGI_FORMAT Image11::getDXGIFormat() const
258 {
259     // this should only happen if the image hasn't been redefined first
260     // which would be a bug by the caller
261     ASSERT(mDXGIFormat != DXGI_FORMAT_UNKNOWN);
262 
263     return mDXGIFormat;
264 }
265 
266 // Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as
267 // format/type at input
268 // 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)269 angle::Result Image11::loadData(const gl::Context *context,
270                                 const gl::Box &area,
271                                 const gl::PixelUnpackState &unpack,
272                                 GLenum type,
273                                 const void *input,
274                                 bool applySkipImages)
275 {
276     Context11 *context11 = GetImplAs<Context11>(context);
277 
278     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
279     GLuint inputRowPitch                 = 0;
280     ANGLE_CHECK_GL_MATH(context11, formatInfo.computeRowPitch(type, area.width, unpack.alignment,
281                                                               unpack.rowLength, &inputRowPitch));
282     GLuint inputDepthPitch = 0;
283     ANGLE_CHECK_GL_MATH(context11, formatInfo.computeDepthPitch(area.height, unpack.imageHeight,
284                                                                 inputRowPitch, &inputDepthPitch));
285     GLuint inputSkipBytes = 0;
286     ANGLE_CHECK_GL_MATH(context11,
287                         formatInfo.computeSkipBytes(type, inputRowPitch, inputDepthPitch, unpack,
288                                                     applySkipImages, &inputSkipBytes));
289 
290     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
291     GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
292 
293     const d3d11::Format &d3dFormatInfo =
294         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
295     LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction;
296 
297     D3D11_MAPPED_SUBRESOURCE mappedImage;
298     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
299 
300     uint8_t *offsetMappedData = (static_cast<uint8_t *>(mappedImage.pData) +
301                                  (area.y * mappedImage.RowPitch + area.x * outputPixelSize +
302                                   area.z * mappedImage.DepthPitch));
303     loadFunction(area.width, area.height, area.depth,
304                  static_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch,
305                  inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
306 
307     unmap();
308 
309     return angle::Result::Continue;
310 }
311 
loadCompressedData(const gl::Context * context,const gl::Box & area,const void * input)312 angle::Result Image11::loadCompressedData(const gl::Context *context,
313                                           const gl::Box &area,
314                                           const void *input)
315 {
316     Context11 *context11 = GetImplAs<Context11>(context);
317 
318     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
319     GLuint inputRowPitch                 = 0;
320     ANGLE_CHECK_GL_MATH(
321         context11, formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0, &inputRowPitch));
322     GLuint inputDepthPitch = 0;
323     ANGLE_CHECK_GL_MATH(
324         context11, formatInfo.computeDepthPitch(area.height, 0, inputRowPitch, &inputDepthPitch));
325 
326     const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
327     GLuint outputPixelSize                      = dxgiFormatInfo.pixelBytes;
328     GLuint outputBlockWidth                     = dxgiFormatInfo.blockWidth;
329     GLuint outputBlockHeight                    = dxgiFormatInfo.blockHeight;
330 
331     ASSERT(area.x % outputBlockWidth == 0);
332     ASSERT(area.y % outputBlockHeight == 0);
333 
334     const d3d11::Format &d3dFormatInfo =
335         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
336     LoadImageFunction loadFunction =
337         d3dFormatInfo.getLoadFunctions()(GL_UNSIGNED_BYTE).loadFunction;
338 
339     D3D11_MAPPED_SUBRESOURCE mappedImage;
340     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
341 
342     uint8_t *offsetMappedData =
343         static_cast<uint8_t *>(mappedImage.pData) +
344         ((area.y / outputBlockHeight) * mappedImage.RowPitch +
345          (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch);
346 
347     loadFunction(area.width, area.height, area.depth, static_cast<const uint8_t *>(input),
348                  inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch,
349                  mappedImage.DepthPitch);
350 
351     unmap();
352 
353     return angle::Result::Continue;
354 }
355 
copyFromTexStorage(const gl::Context * context,const gl::ImageIndex & imageIndex,TextureStorage * source)356 angle::Result Image11::copyFromTexStorage(const gl::Context *context,
357                                           const gl::ImageIndex &imageIndex,
358                                           TextureStorage *source)
359 {
360     TextureStorage11 *storage11 = GetAs<TextureStorage11>(source);
361 
362     const TextureHelper11 *textureHelper = nullptr;
363     ANGLE_TRY(storage11->getResource(context, &textureHelper));
364 
365     UINT subresourceIndex = 0;
366     ANGLE_TRY(storage11->getSubresourceIndex(context, imageIndex, &subresourceIndex));
367 
368     gl::Box sourceBox(0, 0, 0, mWidth, mHeight, mDepth);
369     return copyWithoutConversion(context, gl::Offset(), sourceBox, *textureHelper,
370                                  subresourceIndex);
371 }
372 
copyFromFramebuffer(const gl::Context * context,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,const gl::Framebuffer * sourceFBO)373 angle::Result Image11::copyFromFramebuffer(const gl::Context *context,
374                                            const gl::Offset &destOffset,
375                                            const gl::Rectangle &sourceArea,
376                                            const gl::Framebuffer *sourceFBO)
377 {
378     const gl::FramebufferAttachment *srcAttachment = sourceFBO->getReadColorAttachment();
379     ASSERT(srcAttachment);
380 
381     GLenum sourceInternalFormat = srcAttachment->getFormat().info->sizedInternalFormat;
382     const auto &d3d11Format =
383         d3d11::Format::Get(sourceInternalFormat, mRenderer->getRenderer11DeviceCaps());
384 
385     if (d3d11Format.texFormat == mDXGIFormat && sourceInternalFormat == mInternalFormat)
386     {
387         RenderTarget11 *rt11 = nullptr;
388         ANGLE_TRY(srcAttachment->getRenderTarget(context, 0, &rt11));
389         ASSERT(rt11->getTexture().get());
390 
391         TextureHelper11 textureHelper  = rt11->getTexture();
392         unsigned int sourceSubResource = rt11->getSubresourceIndex();
393 
394         gl::Box sourceBox(sourceArea.x, sourceArea.y, 0, sourceArea.width, sourceArea.height, 1);
395         return copyWithoutConversion(context, destOffset, sourceBox, textureHelper,
396                                      sourceSubResource);
397     }
398 
399     // This format requires conversion, so we must copy the texture to staging and manually convert
400     // via readPixels
401     D3D11_MAPPED_SUBRESOURCE mappedImage;
402     ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage));
403 
404     // determine the offset coordinate into the destination buffer
405     const auto &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat);
406     GLsizei rowOffset          = dxgiFormatInfo.pixelBytes * destOffset.x;
407 
408     uint8_t *dataOffset = static_cast<uint8_t *>(mappedImage.pData) +
409                           mappedImage.RowPitch * destOffset.y + rowOffset +
410                           destOffset.z * mappedImage.DepthPitch;
411 
412     const gl::InternalFormat &destFormatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat);
413     const auto &destD3D11Format =
414         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
415 
416     auto loadFunction    = destD3D11Format.getLoadFunctions()(destFormatInfo.type);
417     angle::Result result = angle::Result::Continue;
418     if (loadFunction.requiresConversion)
419     {
420         size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
421         angle::MemoryBuffer *memoryBuffer = nullptr;
422         result = mRenderer->getScratchMemoryBuffer(GetImplAs<Context11>(context), bufferSize,
423                                                    &memoryBuffer);
424 
425         if (result == angle::Result::Continue)
426         {
427             GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
428 
429             result = mRenderer->readFromAttachment(
430                 context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
431                 memoryBufferRowPitch, gl::PixelPackState(), memoryBuffer->data());
432 
433             loadFunction.loadFunction(sourceArea.width, sourceArea.height, 1, memoryBuffer->data(),
434                                       memoryBufferRowPitch, 0, dataOffset, mappedImage.RowPitch,
435                                       mappedImage.DepthPitch);
436         }
437     }
438     else
439     {
440         result = mRenderer->readFromAttachment(
441             context, *srcAttachment, sourceArea, destFormatInfo.format, destFormatInfo.type,
442             mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
443     }
444 
445     unmap();
446     mDirty = true;
447 
448     return result;
449 }
450 
copyWithoutConversion(const gl::Context * context,const gl::Offset & destOffset,const gl::Box & sourceArea,const TextureHelper11 & textureHelper,UINT sourceSubResource)451 angle::Result Image11::copyWithoutConversion(const gl::Context *context,
452                                              const gl::Offset &destOffset,
453                                              const gl::Box &sourceArea,
454                                              const TextureHelper11 &textureHelper,
455                                              UINT sourceSubResource)
456 {
457     // No conversion needed-- use copyback fastpath
458     const TextureHelper11 *stagingTexture = nullptr;
459     unsigned int stagingSubresourceIndex  = 0;
460     ANGLE_TRY(getStagingTexture(context, &stagingTexture, &stagingSubresourceIndex));
461 
462     ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
463 
464     const gl::Extents &extents = textureHelper.getExtents();
465 
466     D3D11_BOX srcBox;
467     srcBox.left   = sourceArea.x;
468     srcBox.right  = sourceArea.x + sourceArea.width;
469     srcBox.top    = sourceArea.y;
470     srcBox.bottom = sourceArea.y + sourceArea.height;
471     srcBox.front  = sourceArea.z;
472     srcBox.back   = sourceArea.z + sourceArea.depth;
473 
474     if (textureHelper.is2D() && textureHelper.getSampleCount() > 1)
475     {
476         D3D11_TEXTURE2D_DESC resolveDesc;
477         resolveDesc.Width              = extents.width;
478         resolveDesc.Height             = extents.height;
479         resolveDesc.MipLevels          = 1;
480         resolveDesc.ArraySize          = 1;
481         resolveDesc.Format             = textureHelper.getFormat();
482         resolveDesc.SampleDesc.Count   = 1;
483         resolveDesc.SampleDesc.Quality = 0;
484         resolveDesc.Usage              = D3D11_USAGE_DEFAULT;
485         resolveDesc.BindFlags          = 0;
486         resolveDesc.CPUAccessFlags     = 0;
487         resolveDesc.MiscFlags          = 0;
488 
489         d3d11::Texture2D resolveTex;
490         ANGLE_TRY(
491             mRenderer->allocateResource(GetImplAs<Context11>(context), resolveDesc, &resolveTex));
492 
493         deviceContext->ResolveSubresource(resolveTex.get(), 0, textureHelper.get(),
494                                           sourceSubResource, textureHelper.getFormat());
495 
496         deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
497                                              destOffset.x, destOffset.y, destOffset.z,
498                                              resolveTex.get(), 0, &srcBox);
499     }
500     else
501     {
502         deviceContext->CopySubresourceRegion(stagingTexture->get(), stagingSubresourceIndex,
503                                              destOffset.x, destOffset.y, destOffset.z,
504                                              textureHelper.get(), sourceSubResource, &srcBox);
505     }
506 
507     mDirty = true;
508     return angle::Result::Continue;
509 }
510 
getStagingTexture(const gl::Context * context,const TextureHelper11 ** outStagingTexture,unsigned int * outSubresourceIndex)511 angle::Result Image11::getStagingTexture(const gl::Context *context,
512                                          const TextureHelper11 **outStagingTexture,
513                                          unsigned int *outSubresourceIndex)
514 {
515     ANGLE_TRY(createStagingTexture(context));
516 
517     *outStagingTexture   = &mStagingTexture;
518     *outSubresourceIndex = mStagingSubresource;
519     return angle::Result::Continue;
520 }
521 
releaseStagingTexture()522 void Image11::releaseStagingTexture()
523 {
524     mStagingTexture.reset();
525     mStagingTextureSubresourceVerifier.reset();
526 }
527 
createStagingTexture(const gl::Context * context)528 angle::Result Image11::createStagingTexture(const gl::Context *context)
529 {
530     if (mStagingTexture.valid())
531     {
532         return angle::Result::Continue;
533     }
534 
535     ASSERT(mWidth > 0 && mHeight > 0 && mDepth > 0);
536 
537     const DXGI_FORMAT dxgiFormat = getDXGIFormat();
538     const auto &formatInfo =
539         d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps());
540 
541     int lodOffset  = 1;
542     GLsizei width  = mWidth;
543     GLsizei height = mHeight;
544 
545     // adjust size if needed for compressed textures
546     d3d11::MakeValidSize(false, dxgiFormat, &width, &height, &lodOffset);
547 
548     Context11 *context11 = GetImplAs<Context11>(context);
549 
550     switch (mType)
551     {
552         case gl::TextureType::_3D:
553         {
554             D3D11_TEXTURE3D_DESC desc;
555             desc.Width          = width;
556             desc.Height         = height;
557             desc.Depth          = mDepth;
558             desc.MipLevels      = lodOffset + 1;
559             desc.Format         = dxgiFormat;
560             desc.Usage          = D3D11_USAGE_STAGING;
561             desc.BindFlags      = 0;
562             desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
563             desc.MiscFlags      = 0;
564 
565             if (formatInfo.dataInitializerFunction != nullptr)
566             {
567                 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
568                 ANGLE_TRY(d3d11::GenerateInitialTextureData(
569                     context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
570                     mDepth, lodOffset + 1, &initialData));
571 
572                 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
573                                                      initialData.data(), &mStagingTexture));
574             }
575             else
576             {
577                 ANGLE_TRY(
578                     mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
579             }
580 
581             mStagingTexture.setDebugName("Image11::StagingTexture3D");
582             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
583             mStagingTextureSubresourceVerifier.setDesc(desc);
584         }
585         break;
586 
587         case gl::TextureType::_2D:
588         case gl::TextureType::_2DArray:
589         case gl::TextureType::CubeMap:
590         {
591             D3D11_TEXTURE2D_DESC desc;
592             desc.Width              = width;
593             desc.Height             = height;
594             desc.MipLevels          = lodOffset + 1;
595             desc.ArraySize          = 1;
596             desc.Format             = dxgiFormat;
597             desc.SampleDesc.Count   = 1;
598             desc.SampleDesc.Quality = 0;
599             desc.Usage              = D3D11_USAGE_STAGING;
600             desc.BindFlags          = 0;
601             desc.CPUAccessFlags     = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
602             desc.MiscFlags          = 0;
603 
604             if (formatInfo.dataInitializerFunction != nullptr)
605             {
606                 gl::TexLevelArray<D3D11_SUBRESOURCE_DATA> initialData;
607                 ANGLE_TRY(d3d11::GenerateInitialTextureData(
608                     context, mInternalFormat, mRenderer->getRenderer11DeviceCaps(), width, height,
609                     1, lodOffset + 1, &initialData));
610 
611                 ANGLE_TRY(mRenderer->allocateTexture(context11, desc, formatInfo,
612                                                      initialData.data(), &mStagingTexture));
613             }
614             else
615             {
616                 ANGLE_TRY(
617                     mRenderer->allocateTexture(context11, desc, formatInfo, &mStagingTexture));
618             }
619 
620             mStagingTexture.setDebugName("Image11::StagingTexture2D");
621             mStagingSubresource = D3D11CalcSubresource(lodOffset, 0, lodOffset + 1);
622             mStagingTextureSubresourceVerifier.setDesc(desc);
623         }
624         break;
625 
626         default:
627             UNREACHABLE();
628     }
629 
630     mDirty = false;
631     return angle::Result::Continue;
632 }
633 
map(const gl::Context * context,D3D11_MAP mapType,D3D11_MAPPED_SUBRESOURCE * map)634 angle::Result Image11::map(const gl::Context *context,
635                            D3D11_MAP mapType,
636                            D3D11_MAPPED_SUBRESOURCE *map)
637 {
638     // We must recover from the TextureStorage if necessary, even for D3D11_MAP_WRITE.
639     ANGLE_TRY(recoverFromAssociatedStorage(context));
640 
641     const TextureHelper11 *stagingTexture = nullptr;
642     unsigned int subresourceIndex         = 0;
643     ANGLE_TRY(getStagingTexture(context, &stagingTexture, &subresourceIndex));
644 
645     ASSERT(stagingTexture && stagingTexture->valid());
646 
647     ANGLE_TRY(
648         mRenderer->mapResource(context, stagingTexture->get(), subresourceIndex, mapType, 0, map));
649 
650     if (!mStagingTextureSubresourceVerifier.wrap(mapType, map))
651     {
652         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
653         deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
654         Context11 *context11 = GetImplAs<Context11>(context);
655         context11->handleError(GL_OUT_OF_MEMORY,
656                                "Failed to allocate staging texture mapping verifier buffer.",
657                                __FILE__, ANGLE_FUNCTION, __LINE__);
658         return angle::Result::Stop;
659     }
660 
661     mDirty = true;
662 
663     return angle::Result::Continue;
664 }
665 
unmap()666 void Image11::unmap()
667 {
668     if (mStagingTexture.valid())
669     {
670         mStagingTextureSubresourceVerifier.unwrap();
671         ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
672         deviceContext->Unmap(mStagingTexture.get(), mStagingSubresource);
673     }
674 }
675 
676 }  // namespace rx
677