• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2014 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 // TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8 
9 #include "libANGLE/renderer/d3d/TextureD3D.h"
10 
11 #include "common/mathutil.h"
12 #include "common/utilities.h"
13 #include "libANGLE/Buffer.h"
14 #include "libANGLE/Config.h"
15 #include "libANGLE/Context.h"
16 #include "libANGLE/Framebuffer.h"
17 #include "libANGLE/Image.h"
18 #include "libANGLE/Surface.h"
19 #include "libANGLE/Texture.h"
20 #include "libANGLE/formatutils.h"
21 #include "libANGLE/renderer/BufferImpl.h"
22 #include "libANGLE/renderer/d3d/BufferD3D.h"
23 #include "libANGLE/renderer/d3d/ContextD3D.h"
24 #include "libANGLE/renderer/d3d/EGLImageD3D.h"
25 #include "libANGLE/renderer/d3d/ImageD3D.h"
26 #include "libANGLE/renderer/d3d/RenderTargetD3D.h"
27 #include "libANGLE/renderer/d3d/SurfaceD3D.h"
28 #include "libANGLE/renderer/d3d/TextureStorage.h"
29 
30 namespace rx
31 {
32 
33 namespace
34 {
35 
GetUnpackPointer(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset,const uint8_t ** pointerOut)36 angle::Result GetUnpackPointer(const gl::Context *context,
37                                const gl::PixelUnpackState &unpack,
38                                gl::Buffer *unpackBuffer,
39                                const uint8_t *pixels,
40                                ptrdiff_t layerOffset,
41                                const uint8_t **pointerOut)
42 {
43     if (unpackBuffer)
44     {
45         // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not
46         // supported
47         ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
48 
49         // TODO: this is the only place outside of renderer that asks for a buffers raw data.
50         // This functionality should be moved into renderer and the getData method of BufferImpl
51         // removed.
52         BufferD3D *bufferD3D = GetImplAs<BufferD3D>(unpackBuffer);
53         ASSERT(bufferD3D);
54         const uint8_t *bufferData = nullptr;
55         ANGLE_TRY(bufferD3D->getData(context, &bufferData));
56         *pointerOut = bufferData + offset;
57     }
58     else
59     {
60         *pointerOut = pixels;
61     }
62 
63     // Offset the pointer for 2D array layer (if it's valid)
64     if (*pointerOut != nullptr)
65     {
66         *pointerOut += layerOffset;
67     }
68 
69     return angle::Result::Continue;
70 }
71 
IsRenderTargetUsage(GLenum usage)72 bool IsRenderTargetUsage(GLenum usage)
73 {
74     return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
75 }
76 }  // namespace
77 
TextureD3D(const gl::TextureState & state,RendererD3D * renderer)78 TextureD3D::TextureD3D(const gl::TextureState &state, RendererD3D *renderer)
79     : TextureImpl(state),
80       mRenderer(renderer),
81       mDirtyImages(true),
82       mImmutable(false),
83       mTexStorage(nullptr),
84       mTexStorageObserverBinding(this, kTextureStorageObserverMessageIndex),
85       mBaseLevel(0)
86 {}
87 
~TextureD3D()88 TextureD3D::~TextureD3D()
89 {
90     ASSERT(!mTexStorage);
91 }
92 
getNativeTexture(const gl::Context * context,TextureStorage ** outStorage)93 angle::Result TextureD3D::getNativeTexture(const gl::Context *context, TextureStorage **outStorage)
94 {
95     // ensure the underlying texture is created
96     ANGLE_TRY(initializeStorage(context, false));
97 
98     if (mTexStorage)
99     {
100         ANGLE_TRY(updateStorage(context));
101     }
102 
103     ASSERT(outStorage);
104 
105     *outStorage = mTexStorage;
106     return angle::Result::Continue;
107 }
108 
getImageAndSyncFromStorage(const gl::Context * context,const gl::ImageIndex & index,ImageD3D ** outImage)109 angle::Result TextureD3D::getImageAndSyncFromStorage(const gl::Context *context,
110                                                      const gl::ImageIndex &index,
111                                                      ImageD3D **outImage)
112 {
113     ImageD3D *image = getImage(index);
114     if (mTexStorage && mTexStorage->isRenderTarget())
115     {
116         ANGLE_TRY(image->copyFromTexStorage(context, index, mTexStorage));
117         mDirtyImages = true;
118     }
119     *outImage = image;
120     return angle::Result::Continue;
121 }
122 
getLevelZeroWidth() const123 GLint TextureD3D::getLevelZeroWidth() const
124 {
125     ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel());
126     return getBaseLevelWidth() << mBaseLevel;
127 }
128 
getLevelZeroHeight() const129 GLint TextureD3D::getLevelZeroHeight() const
130 {
131     ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelHeight())) > getBaseLevel());
132     return getBaseLevelHeight() << mBaseLevel;
133 }
134 
getLevelZeroDepth() const135 GLint TextureD3D::getLevelZeroDepth() const
136 {
137     return getBaseLevelDepth();
138 }
139 
getBaseLevelWidth() const140 GLint TextureD3D::getBaseLevelWidth() const
141 {
142     const ImageD3D *baseImage = getBaseLevelImage();
143     return (baseImage ? baseImage->getWidth() : 0);
144 }
145 
getBaseLevelHeight() const146 GLint TextureD3D::getBaseLevelHeight() const
147 {
148     const ImageD3D *baseImage = getBaseLevelImage();
149     return (baseImage ? baseImage->getHeight() : 0);
150 }
151 
getBaseLevelDepth() const152 GLint TextureD3D::getBaseLevelDepth() const
153 {
154     const ImageD3D *baseImage = getBaseLevelImage();
155     return (baseImage ? baseImage->getDepth() : 0);
156 }
157 
158 // Note: "base level image" is loosely defined to be any image from the base level,
159 // where in the base of 2D array textures and cube maps there are several. Don't use
160 // the base level image for anything except querying texture format and size.
getBaseLevelInternalFormat() const161 GLenum TextureD3D::getBaseLevelInternalFormat() const
162 {
163     const ImageD3D *baseImage = getBaseLevelImage();
164     return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
165 }
166 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)167 angle::Result TextureD3D::setStorage(const gl::Context *context,
168                                      gl::TextureType type,
169                                      size_t levels,
170                                      GLenum internalFormat,
171                                      const gl::Extents &size)
172 {
173     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
174     return angle::Result::Continue;
175 }
176 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)177 angle::Result TextureD3D::setStorageMultisample(const gl::Context *context,
178                                                 gl::TextureType type,
179                                                 GLsizei samples,
180                                                 GLint internalformat,
181                                                 const gl::Extents &size,
182                                                 bool fixedSampleLocations)
183 {
184     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
185     return angle::Result::Continue;
186 }
187 
setStorageExternalMemory(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size,gl::MemoryObject * memoryObject,GLuint64 offset)188 angle::Result TextureD3D::setStorageExternalMemory(const gl::Context *context,
189                                                    gl::TextureType type,
190                                                    size_t levels,
191                                                    GLenum internalFormat,
192                                                    const gl::Extents &size,
193                                                    gl::MemoryObject *memoryObject,
194                                                    GLuint64 offset)
195 {
196     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
197     return angle::Result::Continue;
198 }
199 
shouldUseSetData(const ImageD3D * image) const200 bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
201 {
202     if (!mRenderer->getFeatures().setDataFasterThanImageUpload.enabled)
203     {
204         return false;
205     }
206 
207     if (image->isDirty())
208     {
209         return false;
210     }
211 
212     gl::InternalFormat internalFormat = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
213 
214     // We can only handle full updates for depth-stencil textures, so to avoid complications
215     // disable them entirely.
216     if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
217     {
218         return false;
219     }
220 
221     // TODO(jmadill): Handle compressed internal formats
222     return (mTexStorage && !internalFormat.compressed);
223 }
224 
setImageImpl(const gl::Context * context,const gl::ImageIndex & index,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset)225 angle::Result TextureD3D::setImageImpl(const gl::Context *context,
226                                        const gl::ImageIndex &index,
227                                        GLenum type,
228                                        const gl::PixelUnpackState &unpack,
229                                        gl::Buffer *unpackBuffer,
230                                        const uint8_t *pixels,
231                                        ptrdiff_t layerOffset)
232 {
233     ImageD3D *image = getImage(index);
234     ASSERT(image);
235 
236     // No-op
237     if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
238     {
239         return angle::Result::Continue;
240     }
241 
242     // We no longer need the "GLenum format" parameter to TexImage to determine what data format
243     // "pixels" contains. From our image internal format we know how many channels to expect, and
244     // "type" gives the format of pixel's components.
245     const uint8_t *pixelData = nullptr;
246     ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
247 
248     if (pixelData != nullptr)
249     {
250         if (shouldUseSetData(image))
251         {
252             ANGLE_TRY(
253                 mTexStorage->setData(context, index, image, nullptr, type, unpack, pixelData));
254         }
255         else
256         {
257             gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(),
258                                   image->getDepth());
259             ANGLE_TRY(image->loadData(context, fullImageArea, unpack, type, pixelData,
260                                       index.usesTex3D()));
261         }
262 
263         mDirtyImages = true;
264     }
265 
266     return angle::Result::Continue;
267 }
268 
subImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,ptrdiff_t layerOffset)269 angle::Result TextureD3D::subImage(const gl::Context *context,
270                                    const gl::ImageIndex &index,
271                                    const gl::Box &area,
272                                    GLenum format,
273                                    GLenum type,
274                                    const gl::PixelUnpackState &unpack,
275                                    gl::Buffer *unpackBuffer,
276                                    const uint8_t *pixels,
277                                    ptrdiff_t layerOffset)
278 {
279     // CPU readback & copy where direct GPU copy is not supported
280     const uint8_t *pixelData = nullptr;
281     ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
282 
283     if (pixelData != nullptr)
284     {
285         ImageD3D *image = getImage(index);
286         ASSERT(image);
287 
288         if (shouldUseSetData(image))
289         {
290             return mTexStorage->setData(context, index, image, &area, type, unpack, pixelData);
291         }
292 
293         ANGLE_TRY(image->loadData(context, area, unpack, type, pixelData, index.usesTex3D()));
294         ANGLE_TRY(commitRegion(context, index, area));
295         mDirtyImages = true;
296     }
297 
298     return angle::Result::Continue;
299 }
300 
setCompressedImageImpl(const gl::Context * context,const gl::ImageIndex & index,const gl::PixelUnpackState & unpack,const uint8_t * pixels,ptrdiff_t layerOffset)301 angle::Result TextureD3D::setCompressedImageImpl(const gl::Context *context,
302                                                  const gl::ImageIndex &index,
303                                                  const gl::PixelUnpackState &unpack,
304                                                  const uint8_t *pixels,
305                                                  ptrdiff_t layerOffset)
306 {
307     ImageD3D *image = getImage(index);
308     ASSERT(image);
309 
310     if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
311     {
312         return angle::Result::Continue;
313     }
314 
315     // We no longer need the "GLenum format" parameter to TexImage to determine what data format
316     // "pixels" contains. From our image internal format we know how many channels to expect, and
317     // "type" gives the format of pixel's components.
318     const uint8_t *pixelData = nullptr;
319     gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
320     ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
321 
322     if (pixelData != nullptr)
323     {
324         gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
325         ANGLE_TRY(image->loadCompressedData(context, fullImageArea, pixelData));
326 
327         mDirtyImages = true;
328     }
329 
330     return angle::Result::Continue;
331 }
332 
subImageCompressed(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,const uint8_t * pixels,ptrdiff_t layerOffset)333 angle::Result TextureD3D::subImageCompressed(const gl::Context *context,
334                                              const gl::ImageIndex &index,
335                                              const gl::Box &area,
336                                              GLenum format,
337                                              const gl::PixelUnpackState &unpack,
338                                              const uint8_t *pixels,
339                                              ptrdiff_t layerOffset)
340 {
341     const uint8_t *pixelData = nullptr;
342     gl::Buffer *unpackBuffer = context->getState().getTargetBuffer(gl::BufferBinding::PixelUnpack);
343     ANGLE_TRY(GetUnpackPointer(context, unpack, unpackBuffer, pixels, layerOffset, &pixelData));
344 
345     if (pixelData != nullptr)
346     {
347         ImageD3D *image = getImage(index);
348         ASSERT(image);
349 
350         ANGLE_TRY(image->loadCompressedData(context, area, pixelData));
351 
352         mDirtyImages = true;
353     }
354 
355     return angle::Result::Continue;
356 }
357 
isFastUnpackable(const gl::Buffer * unpackBuffer,GLenum sizedInternalFormat)358 bool TextureD3D::isFastUnpackable(const gl::Buffer *unpackBuffer, GLenum sizedInternalFormat)
359 {
360     return unpackBuffer != nullptr &&
361            mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
362 }
363 
fastUnpackPixels(const gl::Context * context,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels,const gl::Box & destArea,GLenum sizedInternalFormat,GLenum type,RenderTargetD3D * destRenderTarget)364 angle::Result TextureD3D::fastUnpackPixels(const gl::Context *context,
365                                            const gl::PixelUnpackState &unpack,
366                                            gl::Buffer *unpackBuffer,
367                                            const uint8_t *pixels,
368                                            const gl::Box &destArea,
369                                            GLenum sizedInternalFormat,
370                                            GLenum type,
371                                            RenderTargetD3D *destRenderTarget)
372 {
373     bool check = (unpack.skipRows != 0 || unpack.skipPixels != 0 || unpack.imageHeight != 0 ||
374                   unpack.skipImages != 0);
375     ANGLE_CHECK(GetImplAs<ContextD3D>(context), !check,
376                 "Unimplemented pixel store parameters in fastUnpackPixels", GL_INVALID_OPERATION);
377 
378     // No-op
379     if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
380     {
381         return angle::Result::Continue;
382     }
383 
384     // In order to perform the fast copy through the shader, we must have the right format, and be
385     // able to create a render target.
386     ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
387 
388     uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
389 
390     ANGLE_TRY(mRenderer->fastCopyBufferToTexture(
391         context, unpack, unpackBuffer, static_cast<unsigned int>(offset), destRenderTarget,
392         sizedInternalFormat, type, destArea));
393 
394     return angle::Result::Continue;
395 }
396 
creationLevels(GLsizei width,GLsizei height,GLsizei depth) const397 GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
398 {
399     if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) ||
400         mRenderer->getNativeExtensions().textureNPOTOES)
401     {
402         // Maximum number of levels
403         return gl::log2(std::max(std::max(width, height), depth)) + 1;
404     }
405     else
406     {
407         // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
408         return 1;
409     }
410 }
411 
getStorage()412 TextureStorage *TextureD3D::getStorage()
413 {
414     ASSERT(mTexStorage);
415     return mTexStorage;
416 }
417 
getBaseLevelImage() const418 ImageD3D *TextureD3D::getBaseLevelImage() const
419 {
420     if (mBaseLevel >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
421     {
422         return nullptr;
423     }
424     return getImage(getImageIndex(mBaseLevel, 0));
425 }
426 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)427 angle::Result TextureD3D::setImageExternal(const gl::Context *context,
428                                            gl::TextureType type,
429                                            egl::Stream *stream,
430                                            const egl::Stream::GLTextureDescription &desc)
431 {
432     // Only external images can accept external textures
433     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
434     return angle::Result::Continue;
435 }
436 
generateMipmap(const gl::Context * context)437 angle::Result TextureD3D::generateMipmap(const gl::Context *context)
438 {
439     const GLuint baseLevel = mState.getEffectiveBaseLevel();
440     const GLuint maxLevel  = mState.getMipmapMaxLevel();
441     ASSERT(maxLevel > baseLevel);  // Should be checked before calling this.
442 
443     if (mTexStorage && mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
444     {
445         // Switch to using the mipmapped texture.
446         TextureStorage *textureStorage = nullptr;
447         ANGLE_TRY(getNativeTexture(context, &textureStorage));
448         ANGLE_TRY(textureStorage->useLevelZeroWorkaroundTexture(context, false));
449     }
450 
451     // Set up proper mipmap chain in our Image array.
452     ANGLE_TRY(initMipmapImages(context));
453 
454     if (mTexStorage && mTexStorage->supportsNativeMipmapFunction())
455     {
456         ANGLE_TRY(updateStorage(context));
457 
458         // Generate the mipmap chain using the ad-hoc DirectX function.
459         ANGLE_TRY(mRenderer->generateMipmapUsingD3D(context, mTexStorage, mState));
460     }
461     else
462     {
463         // Generate the mipmap chain, one level at a time.
464         ANGLE_TRY(generateMipmapUsingImages(context, maxLevel));
465     }
466 
467     return angle::Result::Continue;
468 }
469 
generateMipmapUsingImages(const gl::Context * context,const GLuint maxLevel)470 angle::Result TextureD3D::generateMipmapUsingImages(const gl::Context *context,
471                                                     const GLuint maxLevel)
472 {
473     // We know that all layers have the same dimension, for the texture to be complete
474     GLint layerCount = static_cast<GLint>(getLayerCount(mBaseLevel));
475 
476     // When making mipmaps with the setData workaround enabled, the texture storage has
477     // the image data already. For non-render-target storage, we have to pull it out into
478     // an image layer.
479     if (mRenderer->getFeatures().setDataFasterThanImageUpload.enabled && mTexStorage)
480     {
481         if (!mTexStorage->isRenderTarget())
482         {
483             // Copy from the storage mip 0 to Image mip 0
484             for (GLint layer = 0; layer < layerCount; ++layer)
485             {
486                 gl::ImageIndex srcIndex = getImageIndex(mBaseLevel, layer);
487 
488                 ImageD3D *image = getImage(srcIndex);
489                 ANGLE_TRY(image->copyFromTexStorage(context, srcIndex, mTexStorage));
490             }
491         }
492         else
493         {
494             ANGLE_TRY(updateStorage(context));
495         }
496     }
497 
498     // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to
499     // zeroMaxLodWorkaround. The restriction is because Feature Level 9_3 can't create SRVs on
500     // individual levels of the texture. As a result, even if the storage is a rendertarget, we
501     // can't use the GPU to generate the mipmaps without further work. The D3D9 renderer works
502     // around this by copying each level of the texture into its own single-layer GPU texture (in
503     // Blit9::boxFilter). Feature Level 9_3 could do something similar, or it could continue to use
504     // CPU-side mipmap generation, or something else.
505     bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() &&
506                               !(mRenderer->getFeatures().zeroMaxLodWorkaround.enabled));
507 
508     for (GLint layer = 0; layer < layerCount; ++layer)
509     {
510         for (GLuint mip = mBaseLevel + 1; mip <= maxLevel; ++mip)
511         {
512             ASSERT(getLayerCount(mip) == layerCount);
513 
514             gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
515             gl::ImageIndex destIndex   = getImageIndex(mip, layer);
516 
517             if (renderableStorage)
518             {
519                 // GPU-side mipmapping
520                 ANGLE_TRY(mTexStorage->generateMipmap(context, sourceIndex, destIndex));
521             }
522             else
523             {
524                 // CPU-side mipmapping
525                 ANGLE_TRY(
526                     mRenderer->generateMipmap(context, getImage(destIndex), getImage(sourceIndex)));
527             }
528         }
529     }
530 
531     mDirtyImages = true;
532 
533     if (mTexStorage)
534     {
535         ANGLE_TRY(updateStorage(context));
536     }
537 
538     return angle::Result::Continue;
539 }
540 
isBaseImageZeroSize() const541 bool TextureD3D::isBaseImageZeroSize() const
542 {
543     ImageD3D *baseImage = getBaseLevelImage();
544 
545     if (!baseImage || baseImage->getWidth() <= 0 || baseImage->getHeight() <= 0)
546     {
547         return true;
548     }
549 
550     if (baseImage->getType() == gl::TextureType::_3D && baseImage->getDepth() <= 0)
551     {
552         return true;
553     }
554 
555     if (baseImage->getType() == gl::TextureType::_2DArray && getLayerCount(getBaseLevel()) <= 0)
556     {
557         return true;
558     }
559 
560     return false;
561 }
562 
ensureRenderTarget(const gl::Context * context)563 angle::Result TextureD3D::ensureRenderTarget(const gl::Context *context)
564 {
565     ANGLE_TRY(initializeStorage(context, true));
566 
567     // initializeStorage can fail with NoError if the texture is not complete. This is not
568     // an error for incomplete sampling, but it is a big problem for rendering.
569     if (!mTexStorage)
570     {
571         ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
572         return angle::Result::Stop;
573     }
574 
575     if (!isBaseImageZeroSize())
576     {
577         ASSERT(mTexStorage);
578         if (!mTexStorage->isRenderTarget())
579         {
580             TexStoragePointer newRenderTargetStorage(context);
581             ANGLE_TRY(createCompleteStorage(true, &newRenderTargetStorage));
582 
583             ANGLE_TRY(mTexStorage->copyToStorage(context, newRenderTargetStorage.get()));
584             ANGLE_TRY(setCompleteTexStorage(context, newRenderTargetStorage.get()));
585             newRenderTargetStorage.release();
586             // If this texture is used in compute shader, we should invalidate this texture so that
587             // the UAV/SRV is rebound again with this new texture storage in next dispatch call.
588             mTexStorage->invalidateTextures();
589         }
590     }
591 
592     return angle::Result::Continue;
593 }
594 
canCreateRenderTargetForImage(const gl::ImageIndex & index) const595 bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
596 {
597     if (index.getType() == gl::TextureType::_2DMultisample ||
598         index.getType() == gl::TextureType::_2DMultisampleArray)
599     {
600         ASSERT(index.getType() != gl::TextureType::_2DMultisampleArray || index.hasLayer());
601         return true;
602     }
603 
604     ImageD3D *image = getImage(index);
605     ASSERT(image);
606     bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
607     return (image->isRenderableFormat() && levelsComplete);
608 }
609 
commitRegion(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & region)610 angle::Result TextureD3D::commitRegion(const gl::Context *context,
611                                        const gl::ImageIndex &index,
612                                        const gl::Box &region)
613 {
614     if (mTexStorage)
615     {
616         ASSERT(isValidIndex(index));
617         ImageD3D *image = getImage(index);
618         ANGLE_TRY(image->copyToStorage(context, mTexStorage, index, region));
619         image->markClean();
620     }
621 
622     return angle::Result::Continue;
623 }
624 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)625 angle::Result TextureD3D::getAttachmentRenderTarget(const gl::Context *context,
626                                                     GLenum binding,
627                                                     const gl::ImageIndex &imageIndex,
628                                                     GLsizei samples,
629                                                     FramebufferAttachmentRenderTarget **rtOut)
630 {
631     RenderTargetD3D *rtD3D = nullptr;
632     ANGLE_TRY(getRenderTarget(context, imageIndex, samples, &rtD3D));
633     *rtOut = static_cast<FramebufferAttachmentRenderTarget *>(rtD3D);
634     return angle::Result::Continue;
635 }
636 
setBaseLevel(const gl::Context * context,GLuint baseLevel)637 angle::Result TextureD3D::setBaseLevel(const gl::Context *context, GLuint baseLevel)
638 {
639     const int oldStorageWidth  = std::max(1, getLevelZeroWidth());
640     const int oldStorageHeight = std::max(1, getLevelZeroHeight());
641     const int oldStorageDepth  = std::max(1, getLevelZeroDepth());
642     const int oldStorageFormat = getBaseLevelInternalFormat();
643     mBaseLevel                 = baseLevel;
644 
645     // When the base level changes, the texture storage might not be valid anymore, since it could
646     // have been created based on the dimensions of the previous specified level range.
647     const int newStorageWidth  = std::max(1, getLevelZeroWidth());
648     const int newStorageHeight = std::max(1, getLevelZeroHeight());
649     const int newStorageDepth  = std::max(1, getLevelZeroDepth());
650     const int newStorageFormat = getBaseLevelInternalFormat();
651     if (mTexStorage &&
652         (newStorageWidth != oldStorageWidth || newStorageHeight != oldStorageHeight ||
653          newStorageDepth != oldStorageDepth || newStorageFormat != oldStorageFormat))
654     {
655         markAllImagesDirty();
656 
657         // Iterate over all images, and backup the content if it's been used as a render target. The
658         // D3D11 backend can automatically restore images on storage destroy, but it only works for
659         // images that have been associated with the texture storage before, which is insufficient
660         // here.
661         if (mTexStorage->isRenderTarget())
662         {
663             gl::ImageIndexIterator iterator = imageIterator();
664             while (iterator.hasNext())
665             {
666                 const gl::ImageIndex index    = iterator.next();
667                 const GLsizei samples         = getRenderToTextureSamples();
668                 RenderTargetD3D *renderTarget = nullptr;
669                 ANGLE_TRY(mTexStorage->findRenderTarget(context, index, samples, &renderTarget));
670                 if (renderTarget)
671                 {
672                     ANGLE_TRY(getImage(index)->copyFromTexStorage(context, index, mTexStorage));
673                 }
674             }
675         }
676 
677         ANGLE_TRY(releaseTexStorage(context));
678     }
679 
680     return angle::Result::Continue;
681 }
682 
syncState(const gl::Context * context,const gl::Texture::DirtyBits & dirtyBits)683 angle::Result TextureD3D::syncState(const gl::Context *context,
684                                     const gl::Texture::DirtyBits &dirtyBits)
685 {
686     // This could be improved using dirty bits.
687     return angle::Result::Continue;
688 }
689 
releaseTexStorage(const gl::Context * context)690 angle::Result TextureD3D::releaseTexStorage(const gl::Context *context)
691 {
692     if (!mTexStorage)
693     {
694         return angle::Result::Continue;
695     }
696 
697     auto err = mTexStorage->onDestroy(context);
698     SafeDelete(mTexStorage);
699     return err;
700 }
701 
onDestroy(const gl::Context * context)702 void TextureD3D::onDestroy(const gl::Context *context)
703 {
704     (void)releaseTexStorage(context);
705 }
706 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)707 angle::Result TextureD3D::initializeContents(const gl::Context *context,
708                                              const gl::ImageIndex &imageIndex)
709 {
710     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
711     gl::ImageIndex index   = imageIndex;
712 
713     // Special case for D3D11 3D textures. We can't create render targets for individual layers of a
714     // 3D texture, so force the clear to the entire mip. There shouldn't ever be a case where we
715     // would lose existing data.
716     if (index.getType() == gl::TextureType::_3D)
717     {
718         index = gl::ImageIndex::Make3D(index.getLevelIndex(), gl::ImageIndex::kEntireLevel);
719     }
720     else if (index.getType() == gl::TextureType::_2DArray && !index.hasLayer())
721     {
722         std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
723 
724         GLint levelIndex            = index.getLevelIndex();
725         tempLayerCounts[levelIndex] = getLayerCount(levelIndex);
726         gl::ImageIndexIterator iterator =
727             gl::ImageIndexIterator::Make2DArray(levelIndex, levelIndex + 1, tempLayerCounts.data());
728         while (iterator.hasNext())
729         {
730             ANGLE_TRY(initializeContents(context, iterator.next()));
731         }
732         return angle::Result::Continue;
733     }
734     else if (index.getType() == gl::TextureType::_2DMultisampleArray && !index.hasLayer())
735     {
736         std::array<GLint, gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS> tempLayerCounts;
737 
738         ASSERT(index.getLevelIndex() == 0);
739         tempLayerCounts[0] = getLayerCount(0);
740         gl::ImageIndexIterator iterator =
741             gl::ImageIndexIterator::Make2DMultisampleArray(tempLayerCounts.data());
742         while (iterator.hasNext())
743         {
744             ANGLE_TRY(initializeContents(context, iterator.next()));
745         }
746         return angle::Result::Continue;
747     }
748 
749     // Force image clean.
750     ImageD3D *image = getImage(index);
751     if (image)
752     {
753         image->markClean();
754     }
755 
756     // Fast path: can use a render target clear.
757     // We don't use the fast path with the zero max lod workaround because it would introduce a race
758     // between the rendertarget and the staging images.
759     const angle::FeaturesD3D &features = mRenderer->getFeatures();
760     bool shouldUseClear                = (image == nullptr);
761     if (canCreateRenderTargetForImage(index) && !features.zeroMaxLodWorkaround.enabled &&
762         (shouldUseClear || features.allowClearForRobustResourceInit.enabled))
763     {
764         ANGLE_TRY(ensureRenderTarget(context));
765         ASSERT(mTexStorage);
766         RenderTargetD3D *renderTarget = nullptr;
767         ANGLE_TRY(mTexStorage->getRenderTarget(context, index, 0, &renderTarget));
768         ANGLE_TRY(mRenderer->initRenderTarget(context, renderTarget));
769         return angle::Result::Continue;
770     }
771 
772     ASSERT(image != nullptr);
773 
774     // Slow path: non-renderable texture or the texture levels aren't set up.
775     const auto &formatInfo = gl::GetSizedInternalFormatInfo(image->getInternalFormat());
776 
777     GLuint imageBytes = 0;
778     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeRowPitch(formatInfo.type, image->getWidth(),
779                                                                1, 0, &imageBytes));
780     imageBytes *= image->getHeight() * image->getDepth();
781 
782     gl::PixelUnpackState zeroDataUnpackState;
783     zeroDataUnpackState.alignment = 1;
784 
785     angle::MemoryBuffer *zeroBuffer = nullptr;
786     ANGLE_CHECK_GL_ALLOC(contextD3D, context->getZeroFilledBuffer(imageBytes, &zeroBuffer));
787 
788     if (shouldUseSetData(image))
789     {
790         ANGLE_TRY(mTexStorage->setData(context, index, image, nullptr, formatInfo.type,
791                                        zeroDataUnpackState, zeroBuffer->data()));
792     }
793     else
794     {
795         gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
796         ANGLE_TRY(image->loadData(context, fullImageArea, zeroDataUnpackState, formatInfo.type,
797                                   zeroBuffer->data(), false));
798 
799         // Force an update to the tex storage so we avoid problems with subImage and dirty regions.
800         if (mTexStorage)
801         {
802             ANGLE_TRY(commitRegion(context, index, fullImageArea));
803             image->markClean();
804         }
805         else
806         {
807             mDirtyImages = true;
808         }
809     }
810     return angle::Result::Continue;
811 }
812 
getRenderToTextureSamples()813 GLsizei TextureD3D::getRenderToTextureSamples()
814 {
815     if (mTexStorage)
816     {
817         return mTexStorage->getRenderToTextureSamples();
818     }
819     return 0;
820 }
821 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)822 void TextureD3D::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
823 {
824     onStateChange(message);
825 }
826 
TextureD3D_2D(const gl::TextureState & state,RendererD3D * renderer)827 TextureD3D_2D::TextureD3D_2D(const gl::TextureState &state, RendererD3D *renderer)
828     : TextureD3D(state, renderer)
829 {
830     mEGLImageTarget = false;
831     for (auto &image : mImageArray)
832     {
833         image.reset(renderer->createImage());
834     }
835 }
836 
onDestroy(const gl::Context * context)837 void TextureD3D_2D::onDestroy(const gl::Context *context)
838 {
839     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
840     // for some of their data. If TextureStorage is deleted before the Images, then their data will
841     // be wastefully copied back from the GPU before we delete the Images.
842     for (auto &image : mImageArray)
843     {
844         image.reset();
845     }
846     return TextureD3D::onDestroy(context);
847 }
848 
~TextureD3D_2D()849 TextureD3D_2D::~TextureD3D_2D() {}
850 
getImage(int level,int layer) const851 ImageD3D *TextureD3D_2D::getImage(int level, int layer) const
852 {
853     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
854     ASSERT(layer == 0);
855     return mImageArray[level].get();
856 }
857 
getImage(const gl::ImageIndex & index) const858 ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
859 {
860     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
861     ASSERT(!index.hasLayer());
862     ASSERT(index.getType() == gl::TextureType::_2D ||
863            index.getType() == gl::TextureType::VideoImage);
864     return mImageArray[index.getLevelIndex()].get();
865 }
866 
getLayerCount(int level) const867 GLsizei TextureD3D_2D::getLayerCount(int level) const
868 {
869     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
870     return 1;
871 }
872 
getWidth(GLint level) const873 GLsizei TextureD3D_2D::getWidth(GLint level) const
874 {
875     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
876         return mImageArray[level]->getWidth();
877     else
878         return 0;
879 }
880 
getHeight(GLint level) const881 GLsizei TextureD3D_2D::getHeight(GLint level) const
882 {
883     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
884         return mImageArray[level]->getHeight();
885     else
886         return 0;
887 }
888 
getInternalFormat(GLint level) const889 GLenum TextureD3D_2D::getInternalFormat(GLint level) const
890 {
891     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
892         return mImageArray[level]->getInternalFormat();
893     else
894         return GL_NONE;
895 }
896 
isDepth(GLint level) const897 bool TextureD3D_2D::isDepth(GLint level) const
898 {
899     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
900 }
901 
isSRGB(GLint level) const902 bool TextureD3D_2D::isSRGB(GLint level) const
903 {
904     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
905 }
906 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)907 angle::Result TextureD3D_2D::setImage(const gl::Context *context,
908                                       const gl::ImageIndex &index,
909                                       GLenum internalFormat,
910                                       const gl::Extents &size,
911                                       GLenum format,
912                                       GLenum type,
913                                       const gl::PixelUnpackState &unpack,
914                                       gl::Buffer *unpackBuffer,
915                                       const uint8_t *pixels)
916 {
917     ASSERT((index.getTarget() == gl::TextureTarget::_2D ||
918             index.getTarget() == gl::TextureTarget::VideoImage) &&
919            size.depth == 1);
920 
921     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
922 
923     bool fastUnpacked = false;
924 
925     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
926                             size, false));
927 
928     // Attempt a fast gpu copy of the pixel data to the surface
929     if (mTexStorage)
930     {
931         ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
932     }
933     if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) &&
934         isLevelComplete(index.getLevelIndex()))
935     {
936         // Will try to create RT storage if it does not exist
937         RenderTargetD3D *destRenderTarget = nullptr;
938         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
939 
940         gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
941                          1);
942 
943         ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
944                                    internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
945 
946         // Ensure we don't overwrite our newly initialized data
947         mImageArray[index.getLevelIndex()]->markClean();
948 
949         fastUnpacked = true;
950     }
951 
952     if (!fastUnpacked)
953     {
954         ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
955     }
956 
957     return angle::Result::Continue;
958 }
959 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)960 angle::Result TextureD3D_2D::setSubImage(const gl::Context *context,
961                                          const gl::ImageIndex &index,
962                                          const gl::Box &area,
963                                          GLenum format,
964                                          GLenum type,
965                                          const gl::PixelUnpackState &unpack,
966                                          gl::Buffer *unpackBuffer,
967                                          const uint8_t *pixels)
968 {
969     ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
970 
971     GLenum mipFormat = getInternalFormat(index.getLevelIndex());
972     if (mTexStorage)
973     {
974         ANGLE_TRY(mTexStorage->releaseMultisampledTexStorageForLevel(index.getLevelIndex()));
975     }
976     if (isFastUnpackable(unpackBuffer, mipFormat) && isLevelComplete(index.getLevelIndex()))
977     {
978         RenderTargetD3D *renderTarget = nullptr;
979         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &renderTarget));
980         ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
981 
982         return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
983                                 renderTarget);
984     }
985     else
986     {
987         return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
988                                     pixels, 0);
989     }
990 }
991 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)992 angle::Result TextureD3D_2D::setCompressedImage(const gl::Context *context,
993                                                 const gl::ImageIndex &index,
994                                                 GLenum internalFormat,
995                                                 const gl::Extents &size,
996                                                 const gl::PixelUnpackState &unpack,
997                                                 size_t imageSize,
998                                                 const uint8_t *pixels)
999 {
1000     ASSERT(index.getTarget() == gl::TextureTarget::_2D && size.depth == 1);
1001 
1002     // compressed formats don't have separate sized internal formats-- we can just use the
1003     // compressed format directly
1004     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
1005 
1006     return setCompressedImageImpl(context, index, unpack, pixels, 0);
1007 }
1008 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1009 angle::Result TextureD3D_2D::setCompressedSubImage(const gl::Context *context,
1010                                                    const gl::ImageIndex &index,
1011                                                    const gl::Box &area,
1012                                                    GLenum format,
1013                                                    const gl::PixelUnpackState &unpack,
1014                                                    size_t imageSize,
1015                                                    const uint8_t *pixels)
1016 {
1017     ASSERT(index.getTarget() == gl::TextureTarget::_2D && area.depth == 1 && area.z == 0);
1018     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1019 
1020     return commitRegion(context, index, area);
1021 }
1022 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1023 angle::Result TextureD3D_2D::copyImage(const gl::Context *context,
1024                                        const gl::ImageIndex &index,
1025                                        const gl::Rectangle &sourceArea,
1026                                        GLenum internalFormat,
1027                                        gl::Framebuffer *source)
1028 {
1029     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1030 
1031     const gl::InternalFormat &internalFormatInfo =
1032         gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1033     gl::Extents sourceExtents(sourceArea.width, sourceArea.height, 1);
1034     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1035                             sourceExtents, false));
1036 
1037     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1038 
1039     // Does the read area extend beyond the framebuffer?
1040     bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1041                    sourceArea.x + sourceArea.width > fbSize.width ||
1042                    sourceArea.y + sourceArea.height > fbSize.height;
1043 
1044     // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1045     // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1046     // Same thing for robust resource init.
1047     if (outside &&
1048         (context->getExtensions().webglCompatibility || context->isRobustResourceInitEnabled()))
1049     {
1050         ANGLE_TRY(initializeContents(context, index));
1051     }
1052 
1053     gl::Rectangle clippedArea;
1054     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1055     {
1056         // Empty source area, nothing to do.
1057         return angle::Result::Continue;
1058     }
1059 
1060     gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1061 
1062     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1063     // framebuffer in shaders, so we should use the non-rendering copy path.
1064     if (!canCreateRenderTargetForImage(index) ||
1065         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1066     {
1067         ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, destOffset,
1068                                                                           clippedArea, source));
1069         mDirtyImages = true;
1070     }
1071     else
1072     {
1073         ANGLE_TRY(ensureRenderTarget(context));
1074 
1075         if (clippedArea.width != 0 && clippedArea.height != 0 &&
1076             isValidLevel(index.getLevelIndex()))
1077         {
1078             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1079             ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea, internalFormat,
1080                                              destOffset, mTexStorage, index.getLevelIndex()));
1081         }
1082     }
1083 
1084     return angle::Result::Continue;
1085 }
1086 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1087 angle::Result TextureD3D_2D::copySubImage(const gl::Context *context,
1088                                           const gl::ImageIndex &index,
1089                                           const gl::Offset &destOffset,
1090                                           const gl::Rectangle &sourceArea,
1091                                           gl::Framebuffer *source)
1092 {
1093     ASSERT(index.getTarget() == gl::TextureTarget::_2D && destOffset.z == 0);
1094 
1095     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1096     gl::Rectangle clippedArea;
1097     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1098     {
1099         return angle::Result::Continue;
1100     }
1101     const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1102                                    destOffset.y + clippedArea.y - sourceArea.y, 0);
1103 
1104     // can only make our texture storage to a render target if level 0 is defined (with a width &
1105     // height) and the current level we're copying to is defined (with appropriate format, width &
1106     // height)
1107 
1108     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1109     // framebuffer in shaders, so we should use the non-rendering copy path.
1110     if (!canCreateRenderTargetForImage(index) ||
1111         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1112     {
1113         ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedOffset,
1114                                                                           clippedArea, source));
1115         mDirtyImages = true;
1116     }
1117     else
1118     {
1119         ANGLE_TRY(ensureRenderTarget(context));
1120 
1121         if (isValidLevel(index.getLevelIndex()))
1122         {
1123             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1124             ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea,
1125                                              gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1126                                              clippedOffset, mTexStorage, index.getLevelIndex()));
1127         }
1128     }
1129 
1130     return angle::Result::Continue;
1131 }
1132 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1133 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context,
1134                                          const gl::ImageIndex &index,
1135                                          GLenum internalFormat,
1136                                          GLenum type,
1137                                          size_t sourceLevel,
1138                                          bool unpackFlipY,
1139                                          bool unpackPremultiplyAlpha,
1140                                          bool unpackUnmultiplyAlpha,
1141                                          const gl::Texture *source)
1142 {
1143     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1144 
1145     gl::TextureType sourceType = source->getType();
1146 
1147     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1148     gl::Extents size(
1149         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1150         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1151         1);
1152     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1153                             size, false));
1154 
1155     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1156     gl::Offset destOffset(0, 0, 0);
1157 
1158     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1159     {
1160         ANGLE_TRY(ensureRenderTarget(context));
1161         ASSERT(isValidLevel(index.getLevelIndex()));
1162         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1163 
1164         ANGLE_TRY(mRenderer->copyTexture(
1165             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2D, sourceBox,
1166             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
1167             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
1168             unpackUnmultiplyAlpha));
1169     }
1170     else
1171     {
1172         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
1173         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1174         ImageD3D *sourceImage           = nullptr;
1175         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1176 
1177         ImageD3D *destImage = nullptr;
1178         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1179 
1180         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1181                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1182 
1183         mDirtyImages = true;
1184 
1185         gl::Box destRegion(destOffset, size);
1186         ANGLE_TRY(commitRegion(context, index, destRegion));
1187     }
1188 
1189     return angle::Result::Continue;
1190 }
1191 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,size_t sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1192 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context,
1193                                             const gl::ImageIndex &index,
1194                                             const gl::Offset &destOffset,
1195                                             size_t sourceLevel,
1196                                             const gl::Box &sourceBox,
1197                                             bool unpackFlipY,
1198                                             bool unpackPremultiplyAlpha,
1199                                             bool unpackUnmultiplyAlpha,
1200                                             const gl::Texture *source)
1201 {
1202     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1203 
1204     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1205     {
1206         ANGLE_TRY(ensureRenderTarget(context));
1207         ASSERT(isValidLevel(index.getLevelIndex()));
1208         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1209 
1210         const gl::InternalFormat &internalFormatInfo =
1211             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
1212         ANGLE_TRY(mRenderer->copyTexture(
1213             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2D, sourceBox,
1214             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
1215             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
1216             unpackUnmultiplyAlpha));
1217     }
1218     else
1219     {
1220         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
1221         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1222         ImageD3D *sourceImage           = nullptr;
1223         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1224 
1225         ImageD3D *destImage = nullptr;
1226         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1227 
1228         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1229                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1230 
1231         mDirtyImages = true;
1232 
1233         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
1234         ANGLE_TRY(commitRegion(context, index, destRegion));
1235     }
1236 
1237     return angle::Result::Continue;
1238 }
1239 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)1240 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context,
1241                                                    const gl::Texture *source)
1242 {
1243     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1244     GLint sourceLevel              = 0;
1245 
1246     GLint destLevel = 0;
1247 
1248     GLenum sizedInternalFormat =
1249         source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat;
1250     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1251                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1252     ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false));
1253 
1254     ANGLE_TRY(initializeStorage(context, false));
1255     ASSERT(mTexStorage);
1256 
1257     ANGLE_TRY(
1258         mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel));
1259 
1260     return angle::Result::Continue;
1261 }
1262 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1263 angle::Result TextureD3D_2D::setStorage(const gl::Context *context,
1264                                         gl::TextureType type,
1265                                         size_t levels,
1266                                         GLenum internalFormat,
1267                                         const gl::Extents &size)
1268 {
1269     ASSERT(type == gl::TextureType::_2D && size.depth == 1);
1270 
1271     for (size_t level = 0; level < levels; level++)
1272     {
1273         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
1274                               1);
1275         ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true));
1276     }
1277 
1278     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1279     {
1280         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1281     }
1282 
1283     // TODO(geofflang): Verify storage creation had no errors
1284     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
1285     TexStoragePointer storage(context);
1286     storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width,
1287                                                     size.height, static_cast<int>(levels), false));
1288 
1289     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1290     storage.release();
1291 
1292     ANGLE_TRY(updateStorage(context));
1293 
1294     mImmutable = true;
1295 
1296     return angle::Result::Continue;
1297 }
1298 
bindTexImage(const gl::Context * context,egl::Surface * surface)1299 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface)
1300 {
1301     GLenum internalformat = surface->getConfig()->renderTargetFormat;
1302 
1303     gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
1304     ANGLE_TRY(redefineImage(context, 0, internalformat, size, true));
1305 
1306     ANGLE_TRY(releaseTexStorage(context));
1307 
1308     SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
1309     ASSERT(surfaceD3D);
1310 
1311     mTexStorage     = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
1312     mEGLImageTarget = false;
1313 
1314     mDirtyImages = false;
1315     mImageArray[0]->markClean();
1316 
1317     return angle::Result::Continue;
1318 }
1319 
releaseTexImage(const gl::Context * context)1320 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context)
1321 {
1322     if (mTexStorage)
1323     {
1324         ANGLE_TRY(releaseTexStorage(context));
1325     }
1326 
1327     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1328     {
1329         ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true));
1330     }
1331 
1332     return angle::Result::Continue;
1333 }
1334 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1335 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context,
1336                                                gl::TextureType type,
1337                                                egl::Image *image)
1338 {
1339     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
1340 
1341     // Set the properties of the base mip level from the EGL image
1342     const auto &format = image->getFormat();
1343     gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
1344     ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true));
1345 
1346     // Clear all other images.
1347     for (size_t level = 1; level < mImageArray.size(); level++)
1348     {
1349         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1350     }
1351 
1352     ANGLE_TRY(releaseTexStorage(context));
1353     mImageArray[0]->markClean();
1354 
1355     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
1356     RenderTargetD3D *renderTargetD3D = nullptr;
1357     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
1358 
1359     mTexStorage     = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D);
1360     mEGLImageTarget = true;
1361 
1362     return angle::Result::Continue;
1363 }
1364 
initMipmapImages(const gl::Context * context)1365 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context)
1366 {
1367     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1368     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1369     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
1370     // levels.
1371     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
1372     {
1373         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
1374                               std::max(getLevelZeroHeight() >> level, 1), 1);
1375 
1376         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
1377     }
1378     return angle::Result::Continue;
1379 }
1380 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)1381 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context,
1382                                              const gl::ImageIndex &index,
1383                                              GLsizei samples,
1384                                              RenderTargetD3D **outRT)
1385 {
1386     ASSERT(!index.hasLayer());
1387 
1388     // ensure the underlying texture is created
1389     ANGLE_TRY(ensureRenderTarget(context));
1390     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1391 
1392     return mTexStorage->getRenderTarget(context, index, samples, outRT);
1393 }
1394 
isValidLevel(int level) const1395 bool TextureD3D_2D::isValidLevel(int level) const
1396 {
1397     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1398 }
1399 
isLevelComplete(int level) const1400 bool TextureD3D_2D::isLevelComplete(int level) const
1401 {
1402     if (isImmutable())
1403     {
1404         return true;
1405     }
1406 
1407     GLsizei width  = getLevelZeroWidth();
1408     GLsizei height = getLevelZeroHeight();
1409 
1410     if (width <= 0 || height <= 0)
1411     {
1412         return false;
1413     }
1414 
1415     // The base image level is complete if the width and height are positive
1416     if (level == static_cast<int>(getBaseLevel()))
1417     {
1418         return true;
1419     }
1420 
1421     ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) &&
1422            mImageArray[level] != nullptr);
1423     ImageD3D *image = mImageArray[level].get();
1424 
1425     if (image->getInternalFormat() != getBaseLevelInternalFormat())
1426     {
1427         return false;
1428     }
1429 
1430     if (image->getWidth() != std::max(1, width >> level))
1431     {
1432         return false;
1433     }
1434 
1435     if (image->getHeight() != std::max(1, height >> level))
1436     {
1437         return false;
1438     }
1439 
1440     return true;
1441 }
1442 
isImageComplete(const gl::ImageIndex & index) const1443 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
1444 {
1445     return isLevelComplete(index.getLevelIndex());
1446 }
1447 
1448 // Constructs a native texture resource from the texture images
initializeStorage(const gl::Context * context,bool renderTarget)1449 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, bool renderTarget)
1450 {
1451     // Only initialize the first time this texture is used as a render target or shader resource
1452     if (mTexStorage)
1453     {
1454         return angle::Result::Continue;
1455     }
1456 
1457     // do not attempt to create storage for nonexistant data
1458     if (!isLevelComplete(getBaseLevel()))
1459     {
1460         return angle::Result::Continue;
1461     }
1462 
1463     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
1464 
1465     TexStoragePointer storage(context);
1466     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
1467 
1468     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1469     storage.release();
1470 
1471     ASSERT(mTexStorage);
1472 
1473     // flush image data to the storage
1474     ANGLE_TRY(updateStorage(context));
1475 
1476     return angle::Result::Continue;
1477 }
1478 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const1479 angle::Result TextureD3D_2D::createCompleteStorage(bool renderTarget,
1480                                                    TexStoragePointer *outStorage) const
1481 {
1482     GLsizei width         = getLevelZeroWidth();
1483     GLsizei height        = getLevelZeroHeight();
1484     GLenum internalFormat = getBaseLevelInternalFormat();
1485 
1486     ASSERT(width > 0 && height > 0);
1487 
1488     // use existing storage level count, when previously specified by TexStorage*D
1489     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1490 
1491     bool hintLevelZeroOnly = false;
1492     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1493     {
1494         // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use
1495         // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
1496         hintLevelZeroOnly = true;
1497         for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1498         {
1499             hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1500         }
1501     }
1502 
1503     // TODO(geofflang): Determine if the texture creation succeeded
1504     outStorage->reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height,
1505                                                         levels, hintLevelZeroOnly));
1506 
1507     return angle::Result::Continue;
1508 }
1509 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)1510 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
1511                                                    TextureStorage *newCompleteTexStorage)
1512 {
1513     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
1514     {
1515         for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
1516         {
1517             ANGLE_TRY(
1518                 mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level));
1519         }
1520     }
1521 
1522     ANGLE_TRY(releaseTexStorage(context));
1523     mTexStorage = newCompleteTexStorage;
1524     mTexStorageObserverBinding.bind(mTexStorage);
1525 
1526     mDirtyImages = true;
1527 
1528     return angle::Result::Continue;
1529 }
1530 
updateStorage(const gl::Context * context)1531 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context)
1532 {
1533     if (!mDirtyImages)
1534     {
1535         return angle::Result::Continue;
1536     }
1537 
1538     ASSERT(mTexStorage != nullptr);
1539     GLint storageLevels = mTexStorage->getLevelCount();
1540     for (int level = 0; level < storageLevels; level++)
1541     {
1542         if (mImageArray[level]->isDirty() && isLevelComplete(level))
1543         {
1544             ANGLE_TRY(updateStorageLevel(context, level));
1545         }
1546     }
1547 
1548     mDirtyImages = false;
1549     return angle::Result::Continue;
1550 }
1551 
updateStorageLevel(const gl::Context * context,int level)1552 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level)
1553 {
1554     ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr);
1555     ASSERT(isLevelComplete(level));
1556 
1557     if (mImageArray[level]->isDirty())
1558     {
1559         gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1560         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
1561         ANGLE_TRY(commitRegion(context, index, region));
1562     }
1563 
1564     return angle::Result::Continue;
1565 }
1566 
redefineImage(const gl::Context * context,size_t level,GLenum internalformat,const gl::Extents & size,bool forceRelease)1567 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context,
1568                                            size_t level,
1569                                            GLenum internalformat,
1570                                            const gl::Extents &size,
1571                                            bool forceRelease)
1572 {
1573     ASSERT(size.depth == 1);
1574 
1575     // If there currently is a corresponding storage texture image, it has these parameters
1576     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
1577     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
1578     const GLenum storageFormat = getBaseLevelInternalFormat();
1579 
1580     mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease);
1581     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
1582 
1583     if (mTexStorage)
1584     {
1585         const size_t storageLevels = mTexStorage->getLevelCount();
1586 
1587         // If the storage was from an EGL image, copy it back into local images to preserve it
1588         // while orphaning
1589         if (level != 0 && mEGLImageTarget)
1590         {
1591             ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0),
1592                                                          mTexStorage));
1593         }
1594 
1595         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
1596             size.height != storageHeight ||
1597             internalformat != storageFormat)  // Discard mismatched storage
1598         {
1599             ANGLE_TRY(releaseTexStorage(context));
1600             markAllImagesDirty();
1601         }
1602     }
1603 
1604     // Can't be an EGL image target after being redefined
1605     mEGLImageTarget = false;
1606 
1607     return angle::Result::Continue;
1608 }
1609 
imageIterator() const1610 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1611 {
1612     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1613 }
1614 
getImageIndex(GLint mip,GLint) const1615 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1616 {
1617     // "layer" does not apply to 2D Textures.
1618     return gl::ImageIndex::Make2D(mip);
1619 }
1620 
isValidIndex(const gl::ImageIndex & index) const1621 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1622 {
1623     return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 &&
1624             index.getLevelIndex() < mTexStorage->getLevelCount());
1625 }
1626 
markAllImagesDirty()1627 void TextureD3D_2D::markAllImagesDirty()
1628 {
1629     for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1630     {
1631         mImageArray[i]->markDirty();
1632     }
1633     mDirtyImages = true;
1634 }
1635 
TextureD3D_Cube(const gl::TextureState & state,RendererD3D * renderer)1636 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer)
1637     : TextureD3D(state, renderer)
1638 {
1639     for (auto &face : mImageArray)
1640     {
1641         for (auto &image : face)
1642         {
1643             image.reset(renderer->createImage());
1644         }
1645     }
1646 }
1647 
onDestroy(const gl::Context * context)1648 void TextureD3D_Cube::onDestroy(const gl::Context *context)
1649 {
1650     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
1651     // for some of their data. If TextureStorage is deleted before the Images, then their data will
1652     // be wastefully copied back from the GPU before we delete the Images.
1653     for (auto &face : mImageArray)
1654     {
1655         for (auto &image : face)
1656         {
1657             image.reset();
1658         }
1659     }
1660     return TextureD3D::onDestroy(context);
1661 }
1662 
~TextureD3D_Cube()1663 TextureD3D_Cube::~TextureD3D_Cube() {}
1664 
getImage(int level,int layer) const1665 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
1666 {
1667     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1668     ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount);
1669     return mImageArray[layer][level].get();
1670 }
1671 
getImage(const gl::ImageIndex & index) const1672 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1673 {
1674     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1675     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1676     return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get();
1677 }
1678 
getLayerCount(int level) const1679 GLsizei TextureD3D_Cube::getLayerCount(int level) const
1680 {
1681     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1682     return gl::kCubeFaceCount;
1683 }
1684 
getInternalFormat(GLint level,GLint layer) const1685 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
1686 {
1687     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1688         return mImageArray[layer][level]->getInternalFormat();
1689     else
1690         return GL_NONE;
1691 }
1692 
isDepth(GLint level,GLint layer) const1693 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
1694 {
1695     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
1696 }
1697 
isSRGB(GLint level,GLint layer) const1698 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const
1699 {
1700     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB;
1701 }
1702 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1703 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context,
1704                                                  gl::TextureType type,
1705                                                  egl::Image *image)
1706 {
1707     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
1708     return angle::Result::Continue;
1709 }
1710 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)1711 angle::Result TextureD3D_Cube::setImage(const gl::Context *context,
1712                                         const gl::ImageIndex &index,
1713                                         GLenum internalFormat,
1714                                         const gl::Extents &size,
1715                                         GLenum format,
1716                                         GLenum type,
1717                                         const gl::PixelUnpackState &unpack,
1718                                         gl::Buffer *unpackBuffer,
1719                                         const uint8_t *pixels)
1720 {
1721     ASSERT(size.depth == 1);
1722 
1723     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1724     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1725                             internalFormatInfo.sizedInternalFormat, size, false));
1726 
1727     return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0);
1728 }
1729 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)1730 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context,
1731                                            const gl::ImageIndex &index,
1732                                            const gl::Box &area,
1733                                            GLenum format,
1734                                            GLenum type,
1735                                            const gl::PixelUnpackState &unpack,
1736                                            gl::Buffer *unpackBuffer,
1737                                            const uint8_t *pixels)
1738 {
1739     ASSERT(area.depth == 1 && area.z == 0);
1740     return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels,
1741                                 0);
1742 }
1743 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1744 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context,
1745                                                   const gl::ImageIndex &index,
1746                                                   GLenum internalFormat,
1747                                                   const gl::Extents &size,
1748                                                   const gl::PixelUnpackState &unpack,
1749                                                   size_t imageSize,
1750                                                   const uint8_t *pixels)
1751 {
1752     ASSERT(size.depth == 1);
1753 
1754     // compressed formats don't have separate sized internal formats-- we can just use the
1755     // compressed format directly
1756     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1757                             internalFormat, size, false));
1758 
1759     return setCompressedImageImpl(context, index, unpack, pixels, 0);
1760 }
1761 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)1762 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context,
1763                                                      const gl::ImageIndex &index,
1764                                                      const gl::Box &area,
1765                                                      GLenum format,
1766                                                      const gl::PixelUnpackState &unpack,
1767                                                      size_t imageSize,
1768                                                      const uint8_t *pixels)
1769 {
1770     ASSERT(area.depth == 1 && area.z == 0);
1771 
1772     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1773     return commitRegion(context, index, area);
1774 }
1775 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1776 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context,
1777                                          const gl::ImageIndex &index,
1778                                          const gl::Rectangle &sourceArea,
1779                                          GLenum internalFormat,
1780                                          gl::Framebuffer *source)
1781 {
1782     GLint faceIndex = index.cubeMapFaceIndex();
1783     const gl::InternalFormat &internalFormatInfo =
1784         gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1785 
1786     gl::Extents size(sourceArea.width, sourceArea.height, 1);
1787     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1788                             internalFormatInfo.sizedInternalFormat, size, false));
1789 
1790     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1791 
1792     // Does the read area extend beyond the framebuffer?
1793     bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1794                    sourceArea.x + sourceArea.width > fbSize.width ||
1795                    sourceArea.y + sourceArea.height > fbSize.height;
1796 
1797     // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1798     // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1799     // Same thing for robust resource init.
1800     if (outside &&
1801         (context->getExtensions().webglCompatibility || context->isRobustResourceInitEnabled()))
1802     {
1803         ANGLE_TRY(initializeContents(context, index));
1804     }
1805 
1806     gl::Rectangle clippedArea;
1807     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1808     {
1809         // Empty source area, nothing to do.
1810         return angle::Result::Continue;
1811     }
1812 
1813     gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1814 
1815     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1816     // framebuffer in shaders, so we should use the non-rendering copy path.
1817     if (!canCreateRenderTargetForImage(index) ||
1818         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1819     {
1820         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1821             context, destOffset, clippedArea, source));
1822         mDirtyImages = true;
1823     }
1824     else
1825     {
1826         ANGLE_TRY(ensureRenderTarget(context));
1827 
1828         ASSERT(size.width == size.height);
1829 
1830         if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex()))
1831         {
1832             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1833             ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat,
1834                                                destOffset, mTexStorage, index.getTarget(),
1835                                                index.getLevelIndex()));
1836         }
1837     }
1838 
1839     return angle::Result::Continue;
1840 }
1841 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1842 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context,
1843                                             const gl::ImageIndex &index,
1844                                             const gl::Offset &destOffset,
1845                                             const gl::Rectangle &sourceArea,
1846                                             gl::Framebuffer *source)
1847 {
1848     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1849     gl::Rectangle clippedArea;
1850     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1851     {
1852         return angle::Result::Continue;
1853     }
1854     const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1855                                    destOffset.y + clippedArea.y - sourceArea.y, 0);
1856 
1857     GLint faceIndex = index.cubeMapFaceIndex();
1858 
1859     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1860     // framebuffer in shaders, so we should use the non-rendering copy path.
1861     if (!canCreateRenderTargetForImage(index) ||
1862         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1863     {
1864         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1865             context, clippedOffset, clippedArea, source));
1866         mDirtyImages = true;
1867     }
1868     else
1869     {
1870         ANGLE_TRY(ensureRenderTarget(context));
1871         if (isValidFaceLevel(faceIndex, index.getLevelIndex()))
1872         {
1873             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1874             ANGLE_TRY(mRenderer->copyImageCube(
1875                 context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1876                 clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex()));
1877         }
1878     }
1879 
1880     return angle::Result::Continue;
1881 }
1882 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1883 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context,
1884                                            const gl::ImageIndex &index,
1885                                            GLenum internalFormat,
1886                                            GLenum type,
1887                                            size_t sourceLevel,
1888                                            bool unpackFlipY,
1889                                            bool unpackPremultiplyAlpha,
1890                                            bool unpackUnmultiplyAlpha,
1891                                            const gl::Texture *source)
1892 {
1893     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1894 
1895     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1896 
1897     GLint faceIndex = index.cubeMapFaceIndex();
1898 
1899     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1900     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1901                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1902     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1903                             internalFormatInfo.sizedInternalFormat, size, false));
1904 
1905     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1906     gl::Offset destOffset(0, 0, 0);
1907 
1908     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1909     {
1910 
1911         ANGLE_TRY(ensureRenderTarget(context));
1912         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1913         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1914 
1915         ANGLE_TRY(mRenderer->copyTexture(
1916             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2D, sourceBox,
1917             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
1918             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
1919             unpackUnmultiplyAlpha));
1920     }
1921     else
1922     {
1923         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
1924         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1925         ImageD3D *sourceImage           = nullptr;
1926         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1927 
1928         ImageD3D *destImage = nullptr;
1929         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1930 
1931         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1932                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1933 
1934         mDirtyImages = true;
1935 
1936         gl::Box destRegion(destOffset, size);
1937         ANGLE_TRY(commitRegion(context, index, destRegion));
1938     }
1939 
1940     return angle::Result::Continue;
1941 }
1942 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,size_t sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)1943 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context,
1944                                               const gl::ImageIndex &index,
1945                                               const gl::Offset &destOffset,
1946                                               size_t sourceLevel,
1947                                               const gl::Box &sourceBox,
1948                                               bool unpackFlipY,
1949                                               bool unpackPremultiplyAlpha,
1950                                               bool unpackUnmultiplyAlpha,
1951                                               const gl::Texture *source)
1952 {
1953     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1954 
1955     GLint faceIndex = index.cubeMapFaceIndex();
1956 
1957     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1958     {
1959         ANGLE_TRY(ensureRenderTarget(context));
1960         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1961         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1962 
1963         const gl::InternalFormat &internalFormatInfo =
1964             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex));
1965         ANGLE_TRY(mRenderer->copyTexture(
1966             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2D, sourceBox,
1967             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
1968             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
1969             unpackUnmultiplyAlpha));
1970     }
1971     else
1972     {
1973         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
1974         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1975         ImageD3D *sourceImage           = nullptr;
1976         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1977 
1978         ImageD3D *destImage = nullptr;
1979         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1980 
1981         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1982                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1983 
1984         mDirtyImages = true;
1985 
1986         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
1987         ANGLE_TRY(commitRegion(context, index, destRegion));
1988     }
1989 
1990     return angle::Result::Continue;
1991 }
1992 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1993 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context,
1994                                           gl::TextureType type,
1995                                           size_t levels,
1996                                           GLenum internalFormat,
1997                                           const gl::Extents &size)
1998 {
1999     ASSERT(size.width == size.height);
2000     ASSERT(size.depth == 1);
2001 
2002     for (size_t level = 0; level < levels; level++)
2003     {
2004         GLsizei mipSize = std::max(1, size.width >> level);
2005         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2006         {
2007             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat,
2008                                                     gl::Extents(mipSize, mipSize, 1), true);
2009         }
2010     }
2011 
2012     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2013     {
2014         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2015         {
2016             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE,
2017                                                     gl::Extents(0, 0, 0), true);
2018         }
2019     }
2020 
2021     // TODO(geofflang): Verify storage creation had no errors
2022     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2023 
2024     TexStoragePointer storage(context);
2025     storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width,
2026                                                       static_cast<int>(levels), false));
2027 
2028     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2029     storage.release();
2030 
2031     ANGLE_TRY(updateStorage(context));
2032 
2033     mImmutable = true;
2034 
2035     return angle::Result::Continue;
2036 }
2037 
2038 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const2039 bool TextureD3D_Cube::isCubeComplete() const
2040 {
2041     int baseWidth     = getBaseLevelWidth();
2042     int baseHeight    = getBaseLevelHeight();
2043     GLenum baseFormat = getBaseLevelInternalFormat();
2044 
2045     if (baseWidth <= 0 || baseWidth != baseHeight)
2046     {
2047         return false;
2048     }
2049 
2050     for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++)
2051     {
2052         const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
2053 
2054         if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight ||
2055             faceBaseImage.getInternalFormat() != baseFormat)
2056         {
2057             return false;
2058         }
2059     }
2060 
2061     return true;
2062 }
2063 
bindTexImage(const gl::Context * context,egl::Surface * surface)2064 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface)
2065 {
2066     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2067     return angle::Result::Continue;
2068 }
2069 
releaseTexImage(const gl::Context * context)2070 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context)
2071 {
2072     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2073     return angle::Result::Continue;
2074 }
2075 
initMipmapImages(const gl::Context * context)2076 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context)
2077 {
2078     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2079     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2080     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2081     // levels.
2082     for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2083     {
2084         for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2085         {
2086             int faceLevelSize =
2087                 (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1));
2088             ANGLE_TRY(redefineImage(context, faceIndex, level,
2089                                     mImageArray[faceIndex][baseLevel]->getInternalFormat(),
2090                                     gl::Extents(faceLevelSize, faceLevelSize, 1), false));
2091         }
2092     }
2093     return angle::Result::Continue;
2094 }
2095 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2096 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context,
2097                                                const gl::ImageIndex &index,
2098                                                GLsizei samples,
2099                                                RenderTargetD3D **outRT)
2100 {
2101     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2102 
2103     // ensure the underlying texture is created
2104     ANGLE_TRY(ensureRenderTarget(context));
2105     ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex()));
2106 
2107     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2108 }
2109 
initializeStorage(const gl::Context * context,bool renderTarget)2110 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, bool renderTarget)
2111 {
2112     // Only initialize the first time this texture is used as a render target or shader resource
2113     if (mTexStorage)
2114     {
2115         return angle::Result::Continue;
2116     }
2117 
2118     // do not attempt to create storage for nonexistant data
2119     if (!isFaceLevelComplete(0, getBaseLevel()))
2120     {
2121         return angle::Result::Continue;
2122     }
2123 
2124     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2125 
2126     TexStoragePointer storage(context);
2127     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2128 
2129     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2130     storage.release();
2131 
2132     ASSERT(mTexStorage);
2133 
2134     // flush image data to the storage
2135     ANGLE_TRY(updateStorage(context));
2136 
2137     return angle::Result::Continue;
2138 }
2139 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2140 angle::Result TextureD3D_Cube::createCompleteStorage(bool renderTarget,
2141                                                      TexStoragePointer *outStorage) const
2142 {
2143     GLsizei size = getLevelZeroWidth();
2144 
2145     ASSERT(size > 0);
2146 
2147     // use existing storage level count, when previously specified by TexStorage*D
2148     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
2149 
2150     bool hintLevelZeroOnly = false;
2151     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
2152     {
2153         // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the
2154         // mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
2155         hintLevelZeroOnly = true;
2156         for (int faceIndex = 0;
2157              faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++)
2158         {
2159             for (int level = 1; level < levels && hintLevelZeroOnly; level++)
2160             {
2161                 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() &&
2162                                       isFaceLevelComplete(faceIndex, level));
2163             }
2164         }
2165     }
2166 
2167     // TODO (geofflang): detect if storage creation succeeded
2168     outStorage->reset(mRenderer->createTextureStorageCube(
2169         getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly));
2170 
2171     return angle::Result::Continue;
2172 }
2173 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2174 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context,
2175                                                      TextureStorage *newCompleteTexStorage)
2176 {
2177     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
2178     {
2179         for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2180         {
2181             for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
2182             {
2183                 ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube(
2184                     context, newCompleteTexStorage, faceIndex, level));
2185             }
2186         }
2187     }
2188 
2189     ANGLE_TRY(releaseTexStorage(context));
2190     mTexStorage = newCompleteTexStorage;
2191     mTexStorageObserverBinding.bind(mTexStorage);
2192 
2193     mDirtyImages = true;
2194     return angle::Result::Continue;
2195 }
2196 
updateStorage(const gl::Context * context)2197 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context)
2198 {
2199     if (!mDirtyImages)
2200     {
2201         return angle::Result::Continue;
2202     }
2203 
2204     ASSERT(mTexStorage != nullptr);
2205     GLint storageLevels = mTexStorage->getLevelCount();
2206     for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++)
2207     {
2208         for (int level = 0; level < storageLevels; level++)
2209         {
2210             if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
2211             {
2212                 ANGLE_TRY(updateStorageFaceLevel(context, face, level));
2213             }
2214         }
2215     }
2216 
2217     mDirtyImages = false;
2218     return angle::Result::Continue;
2219 }
2220 
isValidFaceLevel(int faceIndex,int level) const2221 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
2222 {
2223     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2224 }
2225 
isFaceLevelComplete(int faceIndex,int level) const2226 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
2227 {
2228     if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2229     {
2230         return false;
2231     }
2232     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2233            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2234            mImageArray[faceIndex][level] != nullptr);
2235 
2236     if (isImmutable())
2237     {
2238         return true;
2239     }
2240 
2241     int levelZeroSize = getLevelZeroWidth();
2242 
2243     if (levelZeroSize <= 0)
2244     {
2245         return false;
2246     }
2247 
2248     // Check that non-zero levels are consistent with the base level.
2249     const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get();
2250 
2251     if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
2252     {
2253         return false;
2254     }
2255 
2256     if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
2257     {
2258         return false;
2259     }
2260 
2261     return true;
2262 }
2263 
isImageComplete(const gl::ImageIndex & index) const2264 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
2265 {
2266     return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex());
2267 }
2268 
updateStorageFaceLevel(const gl::Context * context,int faceIndex,int level)2269 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
2270                                                       int faceIndex,
2271                                                       int level)
2272 {
2273     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2274            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2275            mImageArray[faceIndex][level] != nullptr);
2276     ImageD3D *image = mImageArray[faceIndex][level].get();
2277 
2278     if (image->isDirty())
2279     {
2280         gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
2281         gl::ImageIndex index         = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
2282         gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
2283         ANGLE_TRY(commitRegion(context, index, region));
2284     }
2285 
2286     return angle::Result::Continue;
2287 }
2288 
redefineImage(const gl::Context * context,int faceIndex,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2289 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context,
2290                                              int faceIndex,
2291                                              GLint level,
2292                                              GLenum internalformat,
2293                                              const gl::Extents &size,
2294                                              bool forceRelease)
2295 {
2296     // If there currently is a corresponding storage texture image, it has these parameters
2297     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
2298     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
2299     const GLenum storageFormat = getBaseLevelInternalFormat();
2300 
2301     mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size,
2302                                             forceRelease);
2303     mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty();
2304 
2305     if (mTexStorage)
2306     {
2307         const int storageLevels = mTexStorage->getLevelCount();
2308 
2309         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
2310             size.height != storageHeight ||
2311             internalformat != storageFormat)  // Discard mismatched storage
2312         {
2313             markAllImagesDirty();
2314             ANGLE_TRY(releaseTexStorage(context));
2315         }
2316     }
2317 
2318     return angle::Result::Continue;
2319 }
2320 
imageIterator() const2321 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
2322 {
2323     return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
2324 }
2325 
getImageIndex(GLint mip,GLint layer) const2326 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
2327 {
2328     // The "layer" of the image index corresponds to the cube face
2329     return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
2330 }
2331 
isValidIndex(const gl::ImageIndex & index) const2332 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
2333 {
2334     return (mTexStorage && index.getType() == gl::TextureType::CubeMap &&
2335             gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 &&
2336             index.getLevelIndex() < mTexStorage->getLevelCount());
2337 }
2338 
markAllImagesDirty()2339 void TextureD3D_Cube::markAllImagesDirty()
2340 {
2341     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
2342     {
2343         for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++)
2344         {
2345             mImageArray[dirtyFace][dirtyLevel]->markDirty();
2346         }
2347     }
2348     mDirtyImages = true;
2349 }
2350 
TextureD3D_3D(const gl::TextureState & state,RendererD3D * renderer)2351 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer)
2352     : TextureD3D(state, renderer)
2353 {
2354     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
2355     {
2356         mImageArray[i].reset(renderer->createImage());
2357     }
2358 }
2359 
onDestroy(const gl::Context * context)2360 void TextureD3D_3D::onDestroy(const gl::Context *context)
2361 {
2362     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
2363     // for some of their data. If TextureStorage is deleted before the Images, then their data will
2364     // be wastefully copied back from the GPU before we delete the Images.
2365     for (auto &image : mImageArray)
2366     {
2367         image.reset();
2368     }
2369     return TextureD3D::onDestroy(context);
2370 }
2371 
~TextureD3D_3D()2372 TextureD3D_3D::~TextureD3D_3D() {}
2373 
getImage(int level,int layer) const2374 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
2375 {
2376     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2377     ASSERT(layer == 0);
2378     return mImageArray[level].get();
2379 }
2380 
getImage(const gl::ImageIndex & index) const2381 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
2382 {
2383     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2384     ASSERT(!index.hasLayer());
2385     ASSERT(index.getType() == gl::TextureType::_3D);
2386     return mImageArray[index.getLevelIndex()].get();
2387 }
2388 
getLayerCount(int level) const2389 GLsizei TextureD3D_3D::getLayerCount(int level) const
2390 {
2391     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2392     return 1;
2393 }
2394 
getWidth(GLint level) const2395 GLsizei TextureD3D_3D::getWidth(GLint level) const
2396 {
2397     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2398         return mImageArray[level]->getWidth();
2399     else
2400         return 0;
2401 }
2402 
getHeight(GLint level) const2403 GLsizei TextureD3D_3D::getHeight(GLint level) const
2404 {
2405     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2406         return mImageArray[level]->getHeight();
2407     else
2408         return 0;
2409 }
2410 
getDepth(GLint level) const2411 GLsizei TextureD3D_3D::getDepth(GLint level) const
2412 {
2413     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2414         return mImageArray[level]->getDepth();
2415     else
2416         return 0;
2417 }
2418 
getInternalFormat(GLint level) const2419 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
2420 {
2421     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2422         return mImageArray[level]->getInternalFormat();
2423     else
2424         return GL_NONE;
2425 }
2426 
isDepth(GLint level) const2427 bool TextureD3D_3D::isDepth(GLint level) const
2428 {
2429     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
2430 }
2431 
isSRGB(GLint level) const2432 bool TextureD3D_3D::isSRGB(GLint level) const
2433 {
2434     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
2435 }
2436 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)2437 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context,
2438                                                gl::TextureType type,
2439                                                egl::Image *image)
2440 {
2441     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2442     return angle::Result::Continue;
2443 }
2444 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)2445 angle::Result TextureD3D_3D::setImage(const gl::Context *context,
2446                                       const gl::ImageIndex &index,
2447                                       GLenum internalFormat,
2448                                       const gl::Extents &size,
2449                                       GLenum format,
2450                                       GLenum type,
2451                                       const gl::PixelUnpackState &unpack,
2452                                       gl::Buffer *unpackBuffer,
2453                                       const uint8_t *pixels)
2454 {
2455     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2456     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2457 
2458     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2459                             size, false));
2460 
2461     bool fastUnpacked = false;
2462 
2463     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2464     if (isFastUnpackable(unpackBuffer, internalFormatInfo.sizedInternalFormat) && !size.empty() &&
2465         isLevelComplete(index.getLevelIndex()))
2466     {
2467         // Will try to create RT storage if it does not exist
2468         RenderTargetD3D *destRenderTarget = nullptr;
2469         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2470 
2471         gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
2472                          getDepth(index.getLevelIndex()));
2473 
2474         ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
2475                                    internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
2476 
2477         // Ensure we don't overwrite our newly initialized data
2478         mImageArray[index.getLevelIndex()]->markClean();
2479 
2480         fastUnpacked = true;
2481     }
2482 
2483     if (!fastUnpacked)
2484     {
2485         ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
2486     }
2487 
2488     return angle::Result::Continue;
2489 }
2490 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)2491 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context,
2492                                          const gl::ImageIndex &index,
2493                                          const gl::Box &area,
2494                                          GLenum format,
2495                                          GLenum type,
2496                                          const gl::PixelUnpackState &unpack,
2497                                          gl::Buffer *unpackBuffer,
2498                                          const uint8_t *pixels)
2499 {
2500     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2501 
2502     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2503     GLenum mipFormat = getInternalFormat(index.getLevelIndex());
2504     if (isFastUnpackable(unpackBuffer, mipFormat) && isLevelComplete(index.getLevelIndex()))
2505     {
2506         RenderTargetD3D *destRenderTarget = nullptr;
2507         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2508         ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
2509 
2510         return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
2511                                 destRenderTarget);
2512     }
2513     else
2514     {
2515         return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
2516                                     pixels, 0);
2517     }
2518 }
2519 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)2520 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context,
2521                                                 const gl::ImageIndex &index,
2522                                                 GLenum internalFormat,
2523                                                 const gl::Extents &size,
2524                                                 const gl::PixelUnpackState &unpack,
2525                                                 size_t imageSize,
2526                                                 const uint8_t *pixels)
2527 {
2528     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2529 
2530     // compressed formats don't have separate sized internal formats-- we can just use the
2531     // compressed format directly
2532     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
2533 
2534     return setCompressedImageImpl(context, index, unpack, pixels, 0);
2535 }
2536 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)2537 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context,
2538                                                    const gl::ImageIndex &index,
2539                                                    const gl::Box &area,
2540                                                    GLenum format,
2541                                                    const gl::PixelUnpackState &unpack,
2542                                                    size_t imageSize,
2543                                                    const uint8_t *pixels)
2544 {
2545     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2546 
2547     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
2548     return commitRegion(context, index, area);
2549 }
2550 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)2551 angle::Result TextureD3D_3D::copyImage(const gl::Context *context,
2552                                        const gl::ImageIndex &index,
2553                                        const gl::Rectangle &sourceArea,
2554                                        GLenum internalFormat,
2555                                        gl::Framebuffer *source)
2556 {
2557     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2558     return angle::Result::Continue;
2559 }
2560 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)2561 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context,
2562                                           const gl::ImageIndex &index,
2563                                           const gl::Offset &destOffset,
2564                                           const gl::Rectangle &sourceArea,
2565                                           gl::Framebuffer *source)
2566 {
2567     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2568 
2569     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
2570     gl::Rectangle clippedSourceArea;
2571     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
2572                        &clippedSourceArea))
2573     {
2574         return angle::Result::Continue;
2575     }
2576     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
2577                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
2578                                        destOffset.z);
2579 
2580     // Currently, copying directly to the storage is not possible because it's not possible to
2581     // create an SRV from a single layer of a 3D texture.  Instead, make sure the image is up to
2582     // date before the copy and then copy back to the storage afterwards if needed.
2583     // TODO: Investigate 3D blits in D3D11.
2584 
2585     bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex());
2586     if (syncTexStorage)
2587     {
2588         ANGLE_TRY(
2589             mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage));
2590     }
2591     ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset,
2592                                                                       clippedSourceArea, source));
2593     mDirtyImages = true;
2594 
2595     if (syncTexStorage)
2596     {
2597         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2598     }
2599 
2600     return angle::Result::Continue;
2601 }
2602 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)2603 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context,
2604                                          const gl::ImageIndex &index,
2605                                          GLenum internalFormat,
2606                                          GLenum type,
2607                                          size_t sourceLevel,
2608                                          bool unpackFlipY,
2609                                          bool unpackPremultiplyAlpha,
2610                                          bool unpackUnmultiplyAlpha,
2611                                          const gl::Texture *source)
2612 {
2613     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2614 
2615     gl::TextureType sourceType = source->getType();
2616 
2617     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2618     gl::Extents size(
2619         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2620         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2621         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
2622 
2623     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2624                             size, false));
2625 
2626     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
2627     gl::Offset destOffset(0, 0, 0);
2628     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2629 
2630     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2631     {
2632         ANGLE_TRY(ensureRenderTarget(context));
2633         ASSERT(isValidLevel(index.getLevelIndex()));
2634         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2635 
2636         ANGLE_TRY(mRenderer->copyTexture(
2637             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_3D, sourceBox,
2638             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
2639             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
2640             unpackUnmultiplyAlpha));
2641     }
2642     else
2643     {
2644         gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(static_cast<GLint>(sourceLevel));
2645         ImageD3D *sourceImage      = nullptr;
2646         ImageD3D *destImage        = nullptr;
2647         TextureD3D *sourceD3D      = GetImplAs<TextureD3D>(source);
2648 
2649         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2650         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage));
2651 
2652         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2653                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2654 
2655         mDirtyImages = true;
2656 
2657         gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth);
2658         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2659     }
2660 
2661     return angle::Result::Continue;
2662 }
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,size_t sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)2663 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context,
2664                                             const gl::ImageIndex &index,
2665                                             const gl::Offset &destOffset,
2666                                             size_t sourceLevel,
2667                                             const gl::Box &sourceBox,
2668                                             bool unpackFlipY,
2669                                             bool unpackPremultiplyAlpha,
2670                                             bool unpackUnmultiplyAlpha,
2671                                             const gl::Texture *source)
2672 {
2673     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2674 
2675     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2676 
2677     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2678     {
2679         ANGLE_TRY(ensureRenderTarget(context));
2680         ASSERT(isValidLevel(index.getLevelIndex()));
2681         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2682 
2683         const gl::InternalFormat &internalFormatInfo =
2684             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
2685         ANGLE_TRY(mRenderer->copyTexture(
2686             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_3D, sourceBox,
2687             internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
2688             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
2689             unpackUnmultiplyAlpha));
2690     }
2691     else
2692     {
2693         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(static_cast<GLint>(sourceLevel));
2694         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2695         ImageD3D *sourceImage           = nullptr;
2696         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2697 
2698         ImageD3D *destImage = nullptr;
2699         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2700 
2701         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2702                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2703 
2704         mDirtyImages = true;
2705 
2706         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
2707                            sourceBox.height, sourceBox.depth);
2708         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2709     }
2710 
2711     return angle::Result::Continue;
2712 }
2713 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2714 angle::Result TextureD3D_3D::setStorage(const gl::Context *context,
2715                                         gl::TextureType type,
2716                                         size_t levels,
2717                                         GLenum internalFormat,
2718                                         const gl::Extents &size)
2719 {
2720     ASSERT(type == gl::TextureType::_3D);
2721 
2722     for (size_t level = 0; level < levels; level++)
2723     {
2724         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
2725                               std::max(1, size.depth >> level));
2726         mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true);
2727     }
2728 
2729     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2730     {
2731         mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true);
2732     }
2733 
2734     // TODO(geofflang): Verify storage creation had no errors
2735     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2736     TexStoragePointer storage(context);
2737     storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width,
2738                                                     size.height, size.depth,
2739                                                     static_cast<int>(levels)));
2740 
2741     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2742     storage.release();
2743 
2744     ANGLE_TRY(updateStorage(context));
2745 
2746     mImmutable = true;
2747 
2748     return angle::Result::Continue;
2749 }
2750 
bindTexImage(const gl::Context * context,egl::Surface * surface)2751 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface)
2752 {
2753     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2754     return angle::Result::Continue;
2755 }
2756 
releaseTexImage(const gl::Context * context)2757 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context)
2758 {
2759     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2760     return angle::Result::Continue;
2761 }
2762 
initMipmapImages(const gl::Context * context)2763 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context)
2764 {
2765     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2766     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2767     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2768     // levels.
2769     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2770     {
2771         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
2772                               std::max(getLevelZeroHeight() >> level, 1),
2773                               std::max(getLevelZeroDepth() >> level, 1));
2774         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
2775     }
2776 
2777     return angle::Result::Continue;
2778 }
2779 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2780 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context,
2781                                              const gl::ImageIndex &index,
2782                                              GLsizei samples,
2783                                              RenderTargetD3D **outRT)
2784 {
2785     // ensure the underlying texture is created
2786     ANGLE_TRY(ensureRenderTarget(context));
2787 
2788     if (index.hasLayer())
2789     {
2790         ANGLE_TRY(updateStorage(context));
2791     }
2792     else
2793     {
2794         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2795     }
2796 
2797     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2798 }
2799 
initializeStorage(const gl::Context * context,bool renderTarget)2800 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, bool renderTarget)
2801 {
2802     // Only initialize the first time this texture is used as a render target or shader resource
2803     if (mTexStorage)
2804     {
2805         return angle::Result::Continue;
2806     }
2807 
2808     // do not attempt to create storage for nonexistant data
2809     if (!isLevelComplete(getBaseLevel()))
2810     {
2811         return angle::Result::Continue;
2812     }
2813 
2814     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2815 
2816     TexStoragePointer storage(context);
2817     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2818 
2819     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2820     storage.release();
2821 
2822     ASSERT(mTexStorage);
2823 
2824     // flush image data to the storage
2825     ANGLE_TRY(updateStorage(context));
2826 
2827     return angle::Result::Continue;
2828 }
2829 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2830 angle::Result TextureD3D_3D::createCompleteStorage(bool renderTarget,
2831                                                    TexStoragePointer *outStorage) const
2832 {
2833     GLsizei width         = getLevelZeroWidth();
2834     GLsizei height        = getLevelZeroHeight();
2835     GLsizei depth         = getLevelZeroDepth();
2836     GLenum internalFormat = getBaseLevelInternalFormat();
2837 
2838     ASSERT(width > 0 && height > 0 && depth > 0);
2839 
2840     // use existing storage level count, when previously specified by TexStorage*D
2841     GLint levels =
2842         (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2843 
2844     // TODO: Verify creation of the storage succeeded
2845     outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height,
2846                                                         depth, levels));
2847 
2848     return angle::Result::Continue;
2849 }
2850 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2851 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context,
2852                                                    TextureStorage *newCompleteTexStorage)
2853 {
2854     ANGLE_TRY(releaseTexStorage(context));
2855     mTexStorage = newCompleteTexStorage;
2856     mTexStorageObserverBinding.bind(mTexStorage);
2857     mDirtyImages = true;
2858 
2859     // We do not support managed 3D storage, as that is D3D9/ES2-only
2860     ASSERT(!mTexStorage->isManaged());
2861 
2862     return angle::Result::Continue;
2863 }
2864 
updateStorage(const gl::Context * context)2865 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context)
2866 {
2867     if (!mDirtyImages)
2868     {
2869         return angle::Result::Continue;
2870     }
2871 
2872     ASSERT(mTexStorage != nullptr);
2873     GLint storageLevels = mTexStorage->getLevelCount();
2874     for (int level = 0; level < storageLevels; level++)
2875     {
2876         if (mImageArray[level]->isDirty() && isLevelComplete(level))
2877         {
2878             ANGLE_TRY(updateStorageLevel(context, level));
2879         }
2880     }
2881 
2882     mDirtyImages = false;
2883     return angle::Result::Continue;
2884 }
2885 
isValidLevel(int level) const2886 bool TextureD3D_3D::isValidLevel(int level) const
2887 {
2888     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2889 }
2890 
isLevelComplete(int level) const2891 bool TextureD3D_3D::isLevelComplete(int level) const
2892 {
2893     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2894            mImageArray[level] != nullptr);
2895 
2896     if (isImmutable())
2897     {
2898         return true;
2899     }
2900 
2901     GLsizei width  = getLevelZeroWidth();
2902     GLsizei height = getLevelZeroHeight();
2903     GLsizei depth  = getLevelZeroDepth();
2904 
2905     if (width <= 0 || height <= 0 || depth <= 0)
2906     {
2907         return false;
2908     }
2909 
2910     if (level == static_cast<int>(getBaseLevel()))
2911     {
2912         return true;
2913     }
2914 
2915     ImageD3D *levelImage = mImageArray[level].get();
2916 
2917     if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2918     {
2919         return false;
2920     }
2921 
2922     if (levelImage->getWidth() != std::max(1, width >> level))
2923     {
2924         return false;
2925     }
2926 
2927     if (levelImage->getHeight() != std::max(1, height >> level))
2928     {
2929         return false;
2930     }
2931 
2932     if (levelImage->getDepth() != std::max(1, depth >> level))
2933     {
2934         return false;
2935     }
2936 
2937     return true;
2938 }
2939 
isImageComplete(const gl::ImageIndex & index) const2940 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2941 {
2942     return isLevelComplete(index.getLevelIndex());
2943 }
2944 
updateStorageLevel(const gl::Context * context,int level)2945 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level)
2946 {
2947     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2948            mImageArray[level] != nullptr);
2949     ASSERT(isLevelComplete(level));
2950 
2951     if (mImageArray[level]->isDirty())
2952     {
2953         gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2954         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2955         ANGLE_TRY(commitRegion(context, index, region));
2956     }
2957 
2958     return angle::Result::Continue;
2959 }
2960 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2961 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context,
2962                                            GLint level,
2963                                            GLenum internalformat,
2964                                            const gl::Extents &size,
2965                                            bool forceRelease)
2966 {
2967     // If there currently is a corresponding storage texture image, it has these parameters
2968     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
2969     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
2970     const int storageDepth     = std::max(1, getLevelZeroDepth() >> level);
2971     const GLenum storageFormat = getBaseLevelInternalFormat();
2972 
2973     mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease);
2974     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
2975 
2976     if (mTexStorage)
2977     {
2978         const int storageLevels = mTexStorage->getLevelCount();
2979 
2980         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
2981             size.height != storageHeight || size.depth != storageDepth ||
2982             internalformat != storageFormat)  // Discard mismatched storage
2983         {
2984             markAllImagesDirty();
2985             ANGLE_TRY(releaseTexStorage(context));
2986         }
2987     }
2988 
2989     return angle::Result::Continue;
2990 }
2991 
imageIterator() const2992 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2993 {
2994     return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2995                                           gl::ImageIndex::kEntireLevel,
2996                                           gl::ImageIndex::kEntireLevel);
2997 }
2998 
getImageIndex(GLint mip,GLint) const2999 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
3000 {
3001     // The "layer" here does not apply to 3D images. We use one Image per mip.
3002     return gl::ImageIndex::Make3D(mip);
3003 }
3004 
isValidIndex(const gl::ImageIndex & index) const3005 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
3006 {
3007     return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 &&
3008             index.getLevelIndex() < mTexStorage->getLevelCount());
3009 }
3010 
markAllImagesDirty()3011 void TextureD3D_3D::markAllImagesDirty()
3012 {
3013     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
3014     {
3015         mImageArray[i]->markDirty();
3016     }
3017     mDirtyImages = true;
3018 }
3019 
getLevelZeroDepth() const3020 GLint TextureD3D_3D::getLevelZeroDepth() const
3021 {
3022     ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel());
3023     return getBaseLevelDepth() << getBaseLevel();
3024 }
3025 
TextureD3D_2DArray(const gl::TextureState & state,RendererD3D * renderer)3026 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer)
3027     : TextureD3D(state, renderer)
3028 {
3029     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3030     {
3031         mLayerCounts[level] = 0;
3032         mImageArray[level]  = nullptr;
3033     }
3034 }
3035 
onDestroy(const gl::Context * context)3036 void TextureD3D_2DArray::onDestroy(const gl::Context *context)
3037 {
3038     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
3039     // for some of their data. If TextureStorage is deleted before the Images, then their data will
3040     // be wastefully copied back from the GPU before we delete the Images.
3041     deleteImages();
3042     return TextureD3D::onDestroy(context);
3043 }
3044 
~TextureD3D_2DArray()3045 TextureD3D_2DArray::~TextureD3D_2DArray() {}
3046 
getImage(int level,int layer) const3047 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
3048 {
3049     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3050     ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]);
3051     return (mImageArray[level] ? mImageArray[level][layer] : nullptr);
3052 }
3053 
getImage(const gl::ImageIndex & index) const3054 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
3055 {
3056     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3057     ASSERT(index.hasLayer());
3058     ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) ||
3059            index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]);
3060     ASSERT(index.getType() == gl::TextureType::_2DArray);
3061     return (mImageArray[index.getLevelIndex()]
3062                 ? mImageArray[index.getLevelIndex()][index.getLayerIndex()]
3063                 : nullptr);
3064 }
3065 
getLayerCount(int level) const3066 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
3067 {
3068     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3069     return mLayerCounts[level];
3070 }
3071 
getWidth(GLint level) const3072 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
3073 {
3074     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3075                ? mImageArray[level][0]->getWidth()
3076                : 0;
3077 }
3078 
getHeight(GLint level) const3079 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
3080 {
3081     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3082                ? mImageArray[level][0]->getHeight()
3083                : 0;
3084 }
3085 
getInternalFormat(GLint level) const3086 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
3087 {
3088     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3089                ? mImageArray[level][0]->getInternalFormat()
3090                : GL_NONE;
3091 }
3092 
isDepth(GLint level) const3093 bool TextureD3D_2DArray::isDepth(GLint level) const
3094 {
3095     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
3096 }
3097 
isSRGB(GLint level) const3098 bool TextureD3D_2DArray::isSRGB(GLint level) const
3099 {
3100     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
3101 }
3102 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3103 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context,
3104                                                     gl::TextureType type,
3105                                                     egl::Image *image)
3106 {
3107     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3108     return angle::Result::Continue;
3109 }
3110 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3111 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context,
3112                                            const gl::ImageIndex &index,
3113                                            GLenum internalFormat,
3114                                            const gl::Extents &size,
3115                                            GLenum format,
3116                                            GLenum type,
3117                                            const gl::PixelUnpackState &unpack,
3118                                            gl::Buffer *unpackBuffer,
3119                                            const uint8_t *pixels)
3120 {
3121     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3122 
3123     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3124 
3125     ANGLE_TRY(
3126         redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false));
3127 
3128     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3129 
3130     GLuint inputDepthPitch = 0;
3131     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3132                                         type, size.width, size.height, unpack.alignment,
3133                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3134 
3135     for (int i = 0; i < size.depth; i++)
3136     {
3137         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3138         gl::ImageIndex layerIndex   = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3139         ANGLE_TRY(
3140             setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset));
3141     }
3142 
3143     return angle::Result::Continue;
3144 }
3145 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3146 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context,
3147                                               const gl::ImageIndex &index,
3148                                               const gl::Box &area,
3149                                               GLenum format,
3150                                               GLenum type,
3151                                               const gl::PixelUnpackState &unpack,
3152                                               gl::Buffer *unpackBuffer,
3153                                               const uint8_t *pixels)
3154 {
3155     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3156 
3157     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3158     const gl::InternalFormat &formatInfo =
3159         gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type);
3160     GLuint inputDepthPitch = 0;
3161     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3162                                         type, area.width, area.height, unpack.alignment,
3163                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3164 
3165     for (int i = 0; i < area.depth; i++)
3166     {
3167         int layer                   = area.z + i;
3168         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3169 
3170         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3171 
3172         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3173         ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack,
3174                                        unpackBuffer, pixels, layerOffset));
3175     }
3176 
3177     return angle::Result::Continue;
3178 }
3179 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3180 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context,
3181                                                      const gl::ImageIndex &index,
3182                                                      GLenum internalFormat,
3183                                                      const gl::Extents &size,
3184                                                      const gl::PixelUnpackState &unpack,
3185                                                      size_t imageSize,
3186                                                      const uint8_t *pixels)
3187 {
3188     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3189 
3190     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3191 
3192     // compressed formats don't have separate sized internal formats-- we can just use the
3193     // compressed format directly
3194     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
3195 
3196     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
3197     GLuint inputDepthPitch               = 0;
3198     ANGLE_CHECK_GL_MATH(
3199         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0,
3200                                                  &inputDepthPitch));
3201 
3202     for (int i = 0; i < size.depth; i++)
3203     {
3204         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3205 
3206         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3207         ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset));
3208     }
3209 
3210     return angle::Result::Continue;
3211 }
3212 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3213 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context,
3214                                                         const gl::ImageIndex &index,
3215                                                         const gl::Box &area,
3216                                                         GLenum format,
3217                                                         const gl::PixelUnpackState &unpack,
3218                                                         size_t imageSize,
3219                                                         const uint8_t *pixels)
3220 {
3221     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3222 
3223     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3224 
3225     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
3226     GLuint inputDepthPitch               = 0;
3227     ANGLE_CHECK_GL_MATH(
3228         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0,
3229                                                  &inputDepthPitch));
3230 
3231     for (int i = 0; i < area.depth; i++)
3232     {
3233         int layer                   = area.z + i;
3234         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3235 
3236         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3237 
3238         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3239         ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack,
3240                                                  pixels, layerOffset));
3241         ANGLE_TRY(commitRegion(context, layerIndex, layerArea));
3242     }
3243 
3244     return angle::Result::Continue;
3245 }
3246 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3247 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context,
3248                                             const gl::ImageIndex &index,
3249                                             const gl::Rectangle &sourceArea,
3250                                             GLenum internalFormat,
3251                                             gl::Framebuffer *source)
3252 {
3253     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3254     return angle::Result::Continue;
3255 }
3256 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3257 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context,
3258                                                const gl::ImageIndex &index,
3259                                                const gl::Offset &destOffset,
3260                                                const gl::Rectangle &sourceArea,
3261                                                gl::Framebuffer *source)
3262 {
3263     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3264 
3265     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
3266     gl::Rectangle clippedSourceArea;
3267     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
3268                        &clippedSourceArea))
3269     {
3270         return angle::Result::Continue;
3271     }
3272     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
3273                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
3274                                        destOffset.z);
3275 
3276     if (!canCreateRenderTargetForImage(index))
3277     {
3278         gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
3279         ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer(
3280             context, destLayerOffset, clippedSourceArea, source));
3281         mDirtyImages = true;
3282     }
3283     else
3284     {
3285         ANGLE_TRY(ensureRenderTarget(context));
3286 
3287         if (isValidLevel(index.getLevelIndex()))
3288         {
3289             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3290             ANGLE_TRY(
3291                 mRenderer->copyImage2DArray(context, source, clippedSourceArea,
3292                                             gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
3293                                             clippedDestOffset, mTexStorage, index.getLevelIndex()));
3294         }
3295     }
3296     return angle::Result::Continue;
3297 }
3298 
copyTexture(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,GLenum type,size_t sourceLevel,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)3299 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context,
3300                                               const gl::ImageIndex &index,
3301                                               GLenum internalFormat,
3302                                               GLenum type,
3303                                               size_t sourceLevel,
3304                                               bool unpackFlipY,
3305                                               bool unpackPremultiplyAlpha,
3306                                               bool unpackUnmultiplyAlpha,
3307                                               const gl::Texture *source)
3308 {
3309     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3310 
3311     gl::TextureType sourceType = source->getType();
3312 
3313     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3314     gl::Extents size(
3315         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3316         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3317         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
3318 
3319     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
3320                             size, false));
3321 
3322     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
3323     gl::Offset destOffset(0, 0, 0);
3324 
3325     gl::ImageIndex destIndex =
3326         gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth);
3327 
3328     if (!isSRGB(index.getLevelIndex()) &&
3329         canCreateRenderTargetForImage(
3330             gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth)))
3331     {
3332         ANGLE_TRY(ensureRenderTarget(context));
3333         ASSERT(isValidLevel(index.getLevelIndex()));
3334         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3335         ANGLE_TRY(mRenderer->copyTexture(
3336             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2DArray,
3337             sourceBox, internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
3338             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
3339             unpackUnmultiplyAlpha));
3340     }
3341     else
3342     {
3343         for (int i = 0; i < size.depth; i++)
3344         {
3345             gl::ImageIndex currentSourceDepthIndex =
3346                 gl::ImageIndex::Make2DArray(static_cast<GLint>(sourceLevel), i);
3347             gl::ImageIndex currentDestDepthIndex =
3348                 gl::ImageIndex::Make2DArray(static_cast<GLint>(index.getLevelIndex()), i);
3349             ImageD3D *sourceImage = nullptr;
3350             ImageD3D *destImage   = nullptr;
3351             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3352 
3353             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage));
3354             ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex,
3355                                                             &sourceImage));
3356             gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1);
3357             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset,
3358                                            unpackFlipY, unpackPremultiplyAlpha,
3359                                            unpackUnmultiplyAlpha));
3360         }
3361 
3362         mDirtyImages = true;
3363 
3364         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3365                            sourceBox.height, sourceBox.depth);
3366         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3367     }
3368 
3369     return angle::Result::Continue;
3370 }
3371 
copySubTexture(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,size_t sourceLevel,const gl::Box & sourceBox,bool unpackFlipY,bool unpackPremultiplyAlpha,bool unpackUnmultiplyAlpha,const gl::Texture * source)3372 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context,
3373                                                  const gl::ImageIndex &index,
3374                                                  const gl::Offset &destOffset,
3375                                                  size_t sourceLevel,
3376                                                  const gl::Box &sourceBox,
3377                                                  bool unpackFlipY,
3378                                                  bool unpackPremultiplyAlpha,
3379                                                  bool unpackUnmultiplyAlpha,
3380                                                  const gl::Texture *source)
3381 {
3382     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3383 
3384     gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange(
3385         static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z);
3386 
3387     if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
3388     {
3389         ANGLE_TRY(ensureRenderTarget(context));
3390         ASSERT(isValidLevel(destIndex.getLevelIndex()));
3391         ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex()));
3392 
3393         const gl::InternalFormat &internalFormatInfo =
3394             gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex()));
3395         ANGLE_TRY(mRenderer->copyTexture(
3396             context, source, static_cast<GLint>(sourceLevel), gl::TextureTarget::_2DArray,
3397             sourceBox, internalFormatInfo.format, internalFormatInfo.type, destOffset, mTexStorage,
3398             index.getTarget(), index.getLevelIndex(), unpackFlipY, unpackPremultiplyAlpha,
3399             unpackUnmultiplyAlpha));
3400     }
3401     else
3402     {
3403         for (int i = 0; i < sourceBox.depth; i++)
3404         {
3405             gl::ImageIndex currentSourceIndex =
3406                 gl::ImageIndex::Make2DArray(static_cast<GLint>(sourceLevel), i + sourceBox.z);
3407             gl::ImageIndex currentDestIndex = gl::ImageIndex::Make2DArray(
3408                 static_cast<GLint>(index.getLevelIndex()), i + destOffset.z);
3409 
3410             gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height,
3411                                     1);
3412 
3413             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3414             ImageD3D *sourceImage = nullptr;
3415             ANGLE_TRY(
3416                 sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage));
3417 
3418             ImageD3D *destImage = nullptr;
3419             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage));
3420 
3421             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox,
3422                                            destOffset, unpackFlipY, unpackPremultiplyAlpha,
3423                                            unpackUnmultiplyAlpha));
3424         }
3425 
3426         mDirtyImages = true;
3427 
3428         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3429                            sourceBox.height, sourceBox.depth);
3430         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3431     }
3432 
3433     return angle::Result::Continue;
3434 }
3435 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)3436 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context,
3437                                              gl::TextureType type,
3438                                              size_t levels,
3439                                              GLenum internalFormat,
3440                                              const gl::Extents &size)
3441 {
3442     ASSERT(type == gl::TextureType::_2DArray);
3443 
3444     deleteImages();
3445 
3446     for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
3447     {
3448         gl::Extents levelLayerSize(std::max(1, size.width >> level),
3449                                    std::max(1, size.height >> level), 1);
3450 
3451         mLayerCounts[level] = (level < levels ? size.depth : 0);
3452 
3453         if (mLayerCounts[level] > 0)
3454         {
3455             // Create new images for this level
3456             mImageArray[level] = new ImageD3D *[mLayerCounts[level]];
3457 
3458             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3459             {
3460                 mImageArray[level][layer] = mRenderer->createImage();
3461                 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat,
3462                                                     levelLayerSize, true);
3463             }
3464         }
3465     }
3466 
3467     // TODO(geofflang): Verify storage creation had no errors
3468     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
3469     TexStoragePointer storage(context);
3470     storage.reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width,
3471                                                          size.height, size.depth,
3472                                                          static_cast<int>(levels)));
3473 
3474     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3475     storage.release();
3476 
3477     ANGLE_TRY(updateStorage(context));
3478 
3479     mImmutable = true;
3480 
3481     return angle::Result::Continue;
3482 }
3483 
bindTexImage(const gl::Context * context,egl::Surface * surface)3484 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface)
3485 {
3486     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3487     return angle::Result::Continue;
3488 }
3489 
releaseTexImage(const gl::Context * context)3490 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context)
3491 {
3492     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3493     return angle::Result::Continue;
3494 }
3495 
initMipmapImages(const gl::Context * context)3496 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context)
3497 {
3498     const GLuint baseLevel = mState.getEffectiveBaseLevel();
3499     const GLuint maxLevel  = mState.getMipmapMaxLevel();
3500     int baseWidth          = getLevelZeroWidth();
3501     int baseHeight         = getLevelZeroHeight();
3502     int baseDepth          = getLayerCount(getBaseLevel());
3503     GLenum baseFormat      = getBaseLevelInternalFormat();
3504 
3505     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
3506     // levels.
3507     for (GLuint level = baseLevel + 1u; level <= maxLevel; level++)
3508     {
3509         ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0);
3510         gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
3511                                    std::max(baseHeight >> level, 1), baseDepth);
3512         ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false));
3513     }
3514 
3515     return angle::Result::Continue;
3516 }
3517 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)3518 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context,
3519                                                   const gl::ImageIndex &index,
3520                                                   GLsizei samples,
3521                                                   RenderTargetD3D **outRT)
3522 {
3523     // ensure the underlying texture is created
3524     ANGLE_TRY(ensureRenderTarget(context));
3525     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3526     return mTexStorage->getRenderTarget(context, index, samples, outRT);
3527 }
3528 
initializeStorage(const gl::Context * context,bool renderTarget)3529 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, bool renderTarget)
3530 {
3531     // Only initialize the first time this texture is used as a render target or shader resource
3532     if (mTexStorage)
3533     {
3534         return angle::Result::Continue;
3535     }
3536 
3537     // do not attempt to create storage for nonexistant data
3538     if (!isLevelComplete(getBaseLevel()))
3539     {
3540         return angle::Result::Continue;
3541     }
3542 
3543     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
3544 
3545     TexStoragePointer storage(context);
3546     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
3547 
3548     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3549     storage.release();
3550 
3551     ASSERT(mTexStorage);
3552 
3553     // flush image data to the storage
3554     ANGLE_TRY(updateStorage(context));
3555 
3556     return angle::Result::Continue;
3557 }
3558 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const3559 angle::Result TextureD3D_2DArray::createCompleteStorage(bool renderTarget,
3560                                                         TexStoragePointer *outStorage) const
3561 {
3562     GLsizei width         = getLevelZeroWidth();
3563     GLsizei height        = getLevelZeroHeight();
3564     GLsizei depth         = getLayerCount(getBaseLevel());
3565     GLenum internalFormat = getBaseLevelInternalFormat();
3566 
3567     ASSERT(width > 0 && height > 0 && depth > 0);
3568 
3569     // use existing storage level count, when previously specified by TexStorage*D
3570     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
3571 
3572     // TODO(geofflang): Verify storage creation succeeds
3573     outStorage->reset(mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width,
3574                                                              height, depth, levels));
3575 
3576     return angle::Result::Continue;
3577 }
3578 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)3579 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context,
3580                                                         TextureStorage *newCompleteTexStorage)
3581 {
3582     ANGLE_TRY(releaseTexStorage(context));
3583     mTexStorage = newCompleteTexStorage;
3584     mTexStorageObserverBinding.bind(mTexStorage);
3585     mDirtyImages = true;
3586 
3587     // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
3588     ASSERT(!mTexStorage->isManaged());
3589 
3590     return angle::Result::Continue;
3591 }
3592 
updateStorage(const gl::Context * context)3593 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context)
3594 {
3595     if (!mDirtyImages)
3596     {
3597         return angle::Result::Continue;
3598     }
3599 
3600     ASSERT(mTexStorage != nullptr);
3601     GLint storageLevels = mTexStorage->getLevelCount();
3602     for (int level = 0; level < storageLevels; level++)
3603     {
3604         if (isLevelComplete(level))
3605         {
3606             ANGLE_TRY(updateStorageLevel(context, level));
3607         }
3608     }
3609 
3610     mDirtyImages = false;
3611     return angle::Result::Continue;
3612 }
3613 
isValidLevel(int level) const3614 bool TextureD3D_2DArray::isValidLevel(int level) const
3615 {
3616     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
3617 }
3618 
isLevelComplete(int level) const3619 bool TextureD3D_2DArray::isLevelComplete(int level) const
3620 {
3621     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
3622 
3623     if (isImmutable())
3624     {
3625         return true;
3626     }
3627 
3628     GLsizei width  = getLevelZeroWidth();
3629     GLsizei height = getLevelZeroHeight();
3630 
3631     if (width <= 0 || height <= 0)
3632     {
3633         return false;
3634     }
3635 
3636     // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
3637     // queried.
3638     GLsizei layers = getLayerCount(getBaseLevel());
3639 
3640     if (layers <= 0)
3641     {
3642         return false;
3643     }
3644 
3645     if (level == static_cast<int>(getBaseLevel()))
3646     {
3647         return true;
3648     }
3649 
3650     if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
3651     {
3652         return false;
3653     }
3654 
3655     if (getWidth(level) != std::max(1, width >> level))
3656     {
3657         return false;
3658     }
3659 
3660     if (getHeight(level) != std::max(1, height >> level))
3661     {
3662         return false;
3663     }
3664 
3665     if (getLayerCount(level) != layers)
3666     {
3667         return false;
3668     }
3669 
3670     return true;
3671 }
3672 
isImageComplete(const gl::ImageIndex & index) const3673 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
3674 {
3675     return isLevelComplete(index.getLevelIndex());
3676 }
3677 
updateStorageLevel(const gl::Context * context,int level)3678 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level)
3679 {
3680     ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts)));
3681     ASSERT(isLevelComplete(level));
3682 
3683     for (int layer = 0; layer < mLayerCounts[level]; layer++)
3684     {
3685         ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr);
3686         if (mImageArray[level][layer]->isDirty())
3687         {
3688             gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
3689             gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
3690             ANGLE_TRY(commitRegion(context, index, region));
3691         }
3692     }
3693 
3694     return angle::Result::Continue;
3695 }
3696 
deleteImages()3697 void TextureD3D_2DArray::deleteImages()
3698 {
3699     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3700     {
3701         for (int layer = 0; layer < mLayerCounts[level]; ++layer)
3702         {
3703             delete mImageArray[level][layer];
3704         }
3705         delete[] mImageArray[level];
3706         mImageArray[level]  = nullptr;
3707         mLayerCounts[level] = 0;
3708     }
3709 }
3710 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)3711 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context,
3712                                                 GLint level,
3713                                                 GLenum internalformat,
3714                                                 const gl::Extents &size,
3715                                                 bool forceRelease)
3716 {
3717     // If there currently is a corresponding storage texture image, it has these parameters
3718     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
3719     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
3720     const GLuint baseLevel     = getBaseLevel();
3721     const GLenum storageFormat = getBaseLevelInternalFormat();
3722 
3723     int storageDepth = 0;
3724     if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3725     {
3726         storageDepth = getLayerCount(baseLevel);
3727     }
3728 
3729     // Only reallocate the layers if the size doesn't match
3730     if (size.depth != mLayerCounts[level])
3731     {
3732         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3733         {
3734             SafeDelete(mImageArray[level][layer]);
3735         }
3736         SafeDeleteArray(mImageArray[level]);
3737         mLayerCounts[level] = size.depth;
3738 
3739         if (size.depth > 0)
3740         {
3741             mImageArray[level] = new ImageD3D *[size.depth];
3742             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3743             {
3744                 mImageArray[level][layer] = mRenderer->createImage();
3745             }
3746         }
3747     }
3748 
3749     if (size.depth > 0)
3750     {
3751         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3752         {
3753             mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat,
3754                                                 gl::Extents(size.width, size.height, 1),
3755                                                 forceRelease);
3756             mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty();
3757         }
3758     }
3759 
3760     if (mTexStorage)
3761     {
3762         const int storageLevels = mTexStorage->getLevelCount();
3763 
3764         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3765             size.height != storageHeight || size.depth != storageDepth ||
3766             internalformat != storageFormat)  // Discard mismatched storage
3767         {
3768             markAllImagesDirty();
3769             ANGLE_TRY(releaseTexStorage(context));
3770         }
3771     }
3772 
3773     return angle::Result::Continue;
3774 }
3775 
imageIterator() const3776 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
3777 {
3778     return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
3779 }
3780 
getImageIndex(GLint mip,GLint layer) const3781 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
3782 {
3783     return gl::ImageIndex::Make2DArray(mip, layer);
3784 }
3785 
isValidIndex(const gl::ImageIndex & index) const3786 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
3787 {
3788     // Check for having a storage and the right type of index
3789     if (!mTexStorage || index.getType() != gl::TextureType::_2DArray)
3790     {
3791         return false;
3792     }
3793 
3794     // Check the mip index
3795     if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount())
3796     {
3797         return false;
3798     }
3799 
3800     // Check the layer index
3801     return (!index.hasLayer() || (index.getLayerIndex() >= 0 &&
3802                                   index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]));
3803 }
3804 
markAllImagesDirty()3805 void TextureD3D_2DArray::markAllImagesDirty()
3806 {
3807     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
3808     {
3809         for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
3810         {
3811             mImageArray[dirtyLevel][dirtyLayer]->markDirty();
3812         }
3813     }
3814     mDirtyImages = true;
3815 }
3816 
TextureD3DImmutableBase(const gl::TextureState & state,RendererD3D * renderer)3817 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state,
3818                                                  RendererD3D *renderer)
3819     : TextureD3D(state, renderer)
3820 {}
3821 
~TextureD3DImmutableBase()3822 TextureD3DImmutableBase::~TextureD3DImmutableBase() {}
3823 
getImage(const gl::ImageIndex & index) const3824 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const
3825 {
3826     return nullptr;
3827 }
3828 
setImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3829 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context,
3830                                                 const gl::ImageIndex &index,
3831                                                 GLenum internalFormat,
3832                                                 const gl::Extents &size,
3833                                                 GLenum format,
3834                                                 GLenum type,
3835                                                 const gl::PixelUnpackState &unpack,
3836                                                 gl::Buffer *unpackBuffer,
3837                                                 const uint8_t *pixels)
3838 {
3839     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3840     return angle::Result::Continue;
3841 }
3842 
setSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,GLenum type,const gl::PixelUnpackState & unpack,gl::Buffer * unpackBuffer,const uint8_t * pixels)3843 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context,
3844                                                    const gl::ImageIndex &index,
3845                                                    const gl::Box &area,
3846                                                    GLenum format,
3847                                                    GLenum type,
3848                                                    const gl::PixelUnpackState &unpack,
3849                                                    gl::Buffer *unpackBuffer,
3850                                                    const uint8_t *pixels)
3851 {
3852     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3853     return angle::Result::Continue;
3854 }
3855 
setCompressedImage(const gl::Context * context,const gl::ImageIndex & index,GLenum internalFormat,const gl::Extents & size,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3856 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context,
3857                                                           const gl::ImageIndex &index,
3858                                                           GLenum internalFormat,
3859                                                           const gl::Extents &size,
3860                                                           const gl::PixelUnpackState &unpack,
3861                                                           size_t imageSize,
3862                                                           const uint8_t *pixels)
3863 {
3864     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3865     return angle::Result::Continue;
3866 }
3867 
setCompressedSubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Box & area,GLenum format,const gl::PixelUnpackState & unpack,size_t imageSize,const uint8_t * pixels)3868 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context,
3869                                                              const gl::ImageIndex &index,
3870                                                              const gl::Box &area,
3871                                                              GLenum format,
3872                                                              const gl::PixelUnpackState &unpack,
3873                                                              size_t imageSize,
3874                                                              const uint8_t *pixels)
3875 {
3876     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3877     return angle::Result::Continue;
3878 }
3879 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3880 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context,
3881                                                  const gl::ImageIndex &index,
3882                                                  const gl::Rectangle &sourceArea,
3883                                                  GLenum internalFormat,
3884                                                  gl::Framebuffer *source)
3885 {
3886     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3887     return angle::Result::Continue;
3888 }
3889 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3890 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context,
3891                                                     const gl::ImageIndex &index,
3892                                                     const gl::Offset &destOffset,
3893                                                     const gl::Rectangle &sourceArea,
3894                                                     gl::Framebuffer *source)
3895 {
3896     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3897     return angle::Result::Continue;
3898 }
3899 
bindTexImage(const gl::Context * context,egl::Surface * surface)3900 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context,
3901                                                     egl::Surface *surface)
3902 {
3903     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3904     return angle::Result::Continue;
3905 }
3906 
releaseTexImage(const gl::Context * context)3907 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context)
3908 {
3909     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3910     return angle::Result::Continue;
3911 }
3912 
TextureD3D_External(const gl::TextureState & state,RendererD3D * renderer)3913 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer)
3914     : TextureD3DImmutableBase(state, renderer)
3915 {}
3916 
~TextureD3D_External()3917 TextureD3D_External::~TextureD3D_External() {}
3918 
getLayerCount(int level) const3919 GLsizei TextureD3D_External::getLayerCount(int level) const
3920 {
3921     return 1;
3922 }
3923 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)3924 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context,
3925                                                     gl::TextureType type,
3926                                                     egl::Stream *stream,
3927                                                     const egl::Stream::GLTextureDescription &desc)
3928 {
3929     ASSERT(type == gl::TextureType::External);
3930 
3931     ANGLE_TRY(releaseTexStorage(context));
3932 
3933     // If the stream is null, the external image is unbound and we release the storage
3934     if (stream != nullptr)
3935     {
3936         mTexStorage = mRenderer->createTextureStorageExternal(stream, desc);
3937     }
3938 
3939     return angle::Result::Continue;
3940 }
3941 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3942 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context,
3943                                                      gl::TextureType type,
3944                                                      egl::Image *image)
3945 {
3946     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
3947 
3948     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
3949     RenderTargetD3D *renderTargetD3D = nullptr;
3950     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
3951 
3952     ANGLE_TRY(releaseTexStorage(context));
3953     mTexStorage = mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D);
3954 
3955     return angle::Result::Continue;
3956 }
3957 
initMipmapImages(const gl::Context * context)3958 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context)
3959 {
3960     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3961     return angle::Result::Stop;
3962 }
3963 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)3964 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context,
3965                                                    const gl::ImageIndex &index,
3966                                                    GLsizei samples,
3967                                                    RenderTargetD3D **outRT)
3968 {
3969     UNREACHABLE();
3970     return angle::Result::Stop;
3971 }
3972 
isImageComplete(const gl::ImageIndex & index) const3973 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const
3974 {
3975     return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
3976 }
3977 
initializeStorage(const gl::Context * context,bool renderTarget)3978 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget)
3979 {
3980     // Texture storage is created when an external image is bound
3981     ASSERT(mTexStorage);
3982     return angle::Result::Continue;
3983 }
3984 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const3985 angle::Result TextureD3D_External::createCompleteStorage(bool renderTarget,
3986                                                          TexStoragePointer *outStorage) const
3987 {
3988     UNREACHABLE();
3989     return angle::Result::Continue;
3990 }
3991 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)3992 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context,
3993                                                          TextureStorage *newCompleteTexStorage)
3994 {
3995     UNREACHABLE();
3996     return angle::Result::Continue;
3997 }
3998 
updateStorage(const gl::Context * context)3999 angle::Result TextureD3D_External::updateStorage(const gl::Context *context)
4000 {
4001     // Texture storage does not need to be updated since it is already loaded with the latest
4002     // external image
4003     ASSERT(mTexStorage);
4004     return angle::Result::Continue;
4005 }
4006 
imageIterator() const4007 gl::ImageIndexIterator TextureD3D_External::imageIterator() const
4008 {
4009     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
4010 }
4011 
getImageIndex(GLint mip,GLint) const4012 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const
4013 {
4014     // "layer" does not apply to 2D Textures.
4015     return gl::ImageIndex::Make2D(mip);
4016 }
4017 
isValidIndex(const gl::ImageIndex & index) const4018 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
4019 {
4020     return (mTexStorage && index.getType() == gl::TextureType::External &&
4021             index.getLevelIndex() == 0);
4022 }
4023 
markAllImagesDirty()4024 void TextureD3D_External::markAllImagesDirty()
4025 {
4026     UNREACHABLE();
4027 }
4028 
TextureD3D_2DMultisample(const gl::TextureState & state,RendererD3D * renderer)4029 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state,
4030                                                    RendererD3D *renderer)
4031     : TextureD3DImmutableBase(state, renderer)
4032 {}
4033 
~TextureD3D_2DMultisample()4034 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {}
4035 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4036 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context,
4037                                                               gl::TextureType type,
4038                                                               GLsizei samples,
4039                                                               GLint internalformat,
4040                                                               const gl::Extents &size,
4041                                                               bool fixedSampleLocations)
4042 {
4043     ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1);
4044 
4045     // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do.
4046     // This requires less state in this class.
4047     TexStoragePointer storage(context);
4048     storage.reset(mRenderer->createTextureStorage2DMultisample(internalformat, size.width,
4049                                                                size.height, static_cast<int>(0),
4050                                                                samples, fixedSampleLocations));
4051 
4052     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4053     storage.release();
4054 
4055     mImmutable = true;
4056 
4057     return angle::Result::Continue;
4058 }
4059 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4060 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context,
4061                                                           gl::TextureType type,
4062                                                           egl::Image *image)
4063 {
4064     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4065     return angle::Result::Continue;
4066 }
4067 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4068 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context,
4069                                                         const gl::ImageIndex &index,
4070                                                         GLsizei samples,
4071                                                         RenderTargetD3D **outRT)
4072 {
4073     ASSERT(!index.hasLayer());
4074 
4075     // ensure the underlying texture is created
4076     ANGLE_TRY(ensureRenderTarget(context));
4077 
4078     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4079 }
4080 
imageIterator() const4081 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const
4082 {
4083     return gl::ImageIndexIterator::Make2DMultisample();
4084 }
4085 
getImageIndex(GLint mip,GLint layer) const4086 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const
4087 {
4088     return gl::ImageIndex::Make2DMultisample();
4089 }
4090 
isValidIndex(const gl::ImageIndex & index) const4091 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
4092 {
4093     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample &&
4094             index.getLevelIndex() == 0);
4095 }
4096 
getLayerCount(int level) const4097 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
4098 {
4099     return 1;
4100 }
4101 
markAllImagesDirty()4102 void TextureD3D_2DMultisample::markAllImagesDirty() {}
4103 
initializeStorage(const gl::Context * context,bool renderTarget)4104 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context,
4105                                                           bool renderTarget)
4106 {
4107     // initializeStorage should only be called in a situation where the texture already has storage
4108     // associated with it (storage is created in setStorageMultisample).
4109     ASSERT(mTexStorage);
4110     return angle::Result::Continue;
4111 }
4112 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4113 angle::Result TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget,
4114                                                               TexStoragePointer *outStorage) const
4115 {
4116     UNREACHABLE();
4117     outStorage->reset(mTexStorage);
4118     return angle::Result::Continue;
4119 }
4120 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4121 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context,
4122                                                               TextureStorage *newCompleteTexStorage)
4123 {
4124     // These textures are immutable, so this should only be ever called once.
4125     ASSERT(!mTexStorage);
4126     mTexStorage = newCompleteTexStorage;
4127     mTexStorageObserverBinding.bind(mTexStorage);
4128     return angle::Result::Continue;
4129 }
4130 
updateStorage(const gl::Context * context)4131 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context)
4132 {
4133     return angle::Result::Continue;
4134 }
4135 
initMipmapImages(const gl::Context * context)4136 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context)
4137 {
4138     UNREACHABLE();
4139     return angle::Result::Continue;
4140 }
4141 
isImageComplete(const gl::ImageIndex & index) const4142 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const
4143 {
4144     return true;
4145 }
4146 
TextureD3D_2DMultisampleArray(const gl::TextureState & state,RendererD3D * renderer)4147 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state,
4148                                                              RendererD3D *renderer)
4149     : TextureD3DImmutableBase(state, renderer)
4150 {}
4151 
~TextureD3D_2DMultisampleArray()4152 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {}
4153 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4154 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context,
4155                                                                    gl::TextureType type,
4156                                                                    GLsizei samples,
4157                                                                    GLint internalformat,
4158                                                                    const gl::Extents &size,
4159                                                                    bool fixedSampleLocations)
4160 {
4161     ASSERT(type == gl::TextureType::_2DMultisampleArray);
4162 
4163     mLayerCount = size.depth;
4164 
4165     TexStoragePointer storage(context);
4166     storage.reset(mRenderer->createTextureStorage2DMultisampleArray(
4167         internalformat, size.width, size.height, size.depth, static_cast<int>(0), samples,
4168         fixedSampleLocations));
4169 
4170     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4171     storage.release();
4172 
4173     mImmutable = true;
4174 
4175     return angle::Result::Continue;
4176 }
4177 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4178 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context,
4179                                                                gl::TextureType type,
4180                                                                egl::Image *image)
4181 {
4182     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4183     return angle::Result::Continue;
4184 }
4185 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4186 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context,
4187                                                              const gl::ImageIndex &index,
4188                                                              GLsizei samples,
4189                                                              RenderTargetD3D **outRT)
4190 {
4191     // ensure the underlying texture is created
4192     ANGLE_TRY(ensureRenderTarget(context));
4193 
4194     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4195 }
4196 
imageIterator() const4197 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const
4198 {
4199     return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount);
4200 }
4201 
getImageIndex(GLint mip,GLint layer) const4202 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const
4203 {
4204     return gl::ImageIndex::Make2DMultisampleArray(layer);
4205 }
4206 
isValidIndex(const gl::ImageIndex & index) const4207 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const
4208 {
4209     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray &&
4210             index.getLevelIndex() == 0);
4211 }
4212 
getLayerCount(int level) const4213 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const
4214 {
4215     return mLayerCount;
4216 }
4217 
markAllImagesDirty()4218 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {}
4219 
initializeStorage(const gl::Context * context,bool renderTarget)4220 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context,
4221                                                                bool renderTarget)
4222 {
4223     // initializeStorage should only be called in a situation where the texture already has storage
4224     // associated with it (storage is created in setStorageMultisample).
4225     ASSERT(mTexStorage);
4226     return angle::Result::Continue;
4227 }
4228 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4229 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage(
4230     bool renderTarget,
4231     TexStoragePointer *outStorage) const
4232 {
4233     UNREACHABLE();
4234     outStorage->reset(mTexStorage);
4235     return angle::Result::Continue;
4236 }
4237 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4238 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage(
4239     const gl::Context *context,
4240     TextureStorage *newCompleteTexStorage)
4241 {
4242     // These textures are immutable, so this should only be ever called once.
4243     ASSERT(!mTexStorage);
4244     mTexStorage = newCompleteTexStorage;
4245     mTexStorageObserverBinding.bind(mTexStorage);
4246     return angle::Result::Continue;
4247 }
4248 
updateStorage(const gl::Context * context)4249 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context)
4250 {
4251     return angle::Result::Continue;
4252 }
4253 
initMipmapImages(const gl::Context * context)4254 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context)
4255 {
4256     UNIMPLEMENTED();
4257     return angle::Result::Continue;
4258 }
4259 
isImageComplete(const gl::ImageIndex & index) const4260 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const
4261 {
4262     return true;
4263 }
4264 
4265 }  // namespace rx
4266