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