• 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     }
1150     else
1151     {
1152         ANGLE_TRY(ensureRenderTarget(context));
1153 
1154         if (isValidLevel(index.getLevelIndex()))
1155         {
1156             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1157             ANGLE_TRY(mRenderer->copyImage2D(context, source, clippedArea,
1158                                              gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1159                                              clippedOffset, mTexStorage, index.getLevelIndex()));
1160         }
1161     }
1162 
1163     return angle::Result::Continue;
1164 }
1165 
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)1166 angle::Result TextureD3D_2D::copyTexture(const gl::Context *context,
1167                                          const gl::ImageIndex &index,
1168                                          GLenum internalFormat,
1169                                          GLenum type,
1170                                          GLint sourceLevel,
1171                                          bool unpackFlipY,
1172                                          bool unpackPremultiplyAlpha,
1173                                          bool unpackUnmultiplyAlpha,
1174                                          const gl::Texture *source)
1175 {
1176     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1177 
1178     gl::TextureType sourceType = source->getType();
1179 
1180     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1181     gl::Extents size(
1182         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1183         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
1184         1);
1185     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
1186                             size, false));
1187 
1188     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1189     gl::Offset destOffset(0, 0, 0);
1190 
1191     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1192     {
1193         ANGLE_TRY(ensureRenderTarget(context));
1194         ASSERT(isValidLevel(index.getLevelIndex()));
1195         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1196 
1197         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1198                                          sourceBox, internalFormatInfo.format,
1199                                          internalFormatInfo.type, destOffset, mTexStorage,
1200                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
1201                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1202     }
1203     else
1204     {
1205         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1206         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1207         ImageD3D *sourceImage           = nullptr;
1208         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1209 
1210         ImageD3D *destImage = nullptr;
1211         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1212 
1213         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1214                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1215 
1216         mDirtyImages = true;
1217 
1218         gl::Box destRegion(destOffset, size);
1219         ANGLE_TRY(commitRegion(context, index, destRegion));
1220     }
1221 
1222     return angle::Result::Continue;
1223 }
1224 
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)1225 angle::Result TextureD3D_2D::copySubTexture(const gl::Context *context,
1226                                             const gl::ImageIndex &index,
1227                                             const gl::Offset &destOffset,
1228                                             GLint sourceLevel,
1229                                             const gl::Box &sourceBox,
1230                                             bool unpackFlipY,
1231                                             bool unpackPremultiplyAlpha,
1232                                             bool unpackUnmultiplyAlpha,
1233                                             const gl::Texture *source)
1234 {
1235     ASSERT(index.getTarget() == gl::TextureTarget::_2D);
1236 
1237     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(index))
1238     {
1239         ANGLE_TRY(ensureRenderTarget(context));
1240         ASSERT(isValidLevel(index.getLevelIndex()));
1241         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1242 
1243         const gl::InternalFormat &internalFormatInfo =
1244             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
1245         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1246                                          sourceBox, internalFormatInfo.format,
1247                                          internalFormatInfo.type, destOffset, mTexStorage,
1248                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
1249                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1250     }
1251     else
1252     {
1253         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1254         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1255         ImageD3D *sourceImage           = nullptr;
1256         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1257 
1258         ImageD3D *destImage = nullptr;
1259         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1260 
1261         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1262                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1263 
1264         mDirtyImages = true;
1265 
1266         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
1267         ANGLE_TRY(commitRegion(context, index, destRegion));
1268     }
1269 
1270     return angle::Result::Continue;
1271 }
1272 
copyCompressedTexture(const gl::Context * context,const gl::Texture * source)1273 angle::Result TextureD3D_2D::copyCompressedTexture(const gl::Context *context,
1274                                                    const gl::Texture *source)
1275 {
1276     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1277     GLint sourceLevel              = 0;
1278 
1279     GLint destLevel = 0;
1280 
1281     GLenum sizedInternalFormat =
1282         source->getFormat(sourceTarget, sourceLevel).info->sizedInternalFormat;
1283     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1284                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1285     ANGLE_TRY(redefineImage(context, destLevel, sizedInternalFormat, size, false));
1286 
1287     ANGLE_TRY(initializeStorage(context, false));
1288     ASSERT(mTexStorage);
1289 
1290     ANGLE_TRY(
1291         mRenderer->copyCompressedTexture(context, source, sourceLevel, mTexStorage, destLevel));
1292 
1293     return angle::Result::Continue;
1294 }
1295 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)1296 angle::Result TextureD3D_2D::setStorage(const gl::Context *context,
1297                                         gl::TextureType type,
1298                                         size_t levels,
1299                                         GLenum internalFormat,
1300                                         const gl::Extents &size)
1301 {
1302     ASSERT(type == gl::TextureType::_2D && size.depth == 1);
1303 
1304     for (size_t level = 0; level < levels; level++)
1305     {
1306         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
1307                               1);
1308         ANGLE_TRY(redefineImage(context, level, internalFormat, levelSize, true));
1309     }
1310 
1311     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1312     {
1313         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1314     }
1315 
1316     // TODO(geofflang): Verify storage creation had no errors
1317     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
1318     TexStoragePointer storage(context);
1319     storage.reset(mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width,
1320                                                     size.height, static_cast<int>(levels),
1321                                                     mState.getLabel(), false));
1322 
1323     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1324     storage.release();
1325 
1326     ANGLE_TRY(updateStorage(context));
1327 
1328     mImmutable = true;
1329 
1330     return angle::Result::Continue;
1331 }
1332 
bindTexImage(const gl::Context * context,egl::Surface * surface)1333 angle::Result TextureD3D_2D::bindTexImage(const gl::Context *context, egl::Surface *surface)
1334 {
1335     GLenum internalformat = surface->getConfig()->renderTargetFormat;
1336 
1337     gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
1338     ANGLE_TRY(redefineImage(context, 0, internalformat, size, true));
1339 
1340     ANGLE_TRY(releaseTexStorage(context));
1341 
1342     SurfaceD3D *surfaceD3D = GetImplAs<SurfaceD3D>(surface);
1343     ASSERT(surfaceD3D);
1344 
1345     mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain(), mState.getLabel());
1346     mEGLImageTarget = false;
1347 
1348     mDirtyImages = false;
1349     mImageArray[0]->markClean();
1350 
1351     return angle::Result::Continue;
1352 }
1353 
releaseTexImage(const gl::Context * context)1354 angle::Result TextureD3D_2D::releaseTexImage(const gl::Context *context)
1355 {
1356     if (mTexStorage)
1357     {
1358         ANGLE_TRY(releaseTexStorage(context));
1359     }
1360 
1361     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1362     {
1363         ANGLE_TRY(redefineImage(context, i, GL_NONE, gl::Extents(0, 0, 1), true));
1364     }
1365 
1366     return angle::Result::Continue;
1367 }
1368 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1369 angle::Result TextureD3D_2D::setEGLImageTarget(const gl::Context *context,
1370                                                gl::TextureType type,
1371                                                egl::Image *image)
1372 {
1373     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
1374 
1375     // Set the properties of the base mip level from the EGL image
1376     const auto &format = image->getFormat();
1377     gl::Extents size(static_cast<int>(image->getWidth()), static_cast<int>(image->getHeight()), 1);
1378     ANGLE_TRY(redefineImage(context, 0, format.info->sizedInternalFormat, size, true));
1379 
1380     // Clear all other images.
1381     for (size_t level = 1; level < mImageArray.size(); level++)
1382     {
1383         ANGLE_TRY(redefineImage(context, level, GL_NONE, gl::Extents(0, 0, 1), true));
1384     }
1385 
1386     ANGLE_TRY(releaseTexStorage(context));
1387     mImageArray[0]->markClean();
1388 
1389     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
1390     RenderTargetD3D *renderTargetD3D = nullptr;
1391     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
1392 
1393     mTexStorage =
1394         mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
1395     mEGLImageTarget = true;
1396 
1397     return angle::Result::Continue;
1398 }
1399 
initMipmapImages(const gl::Context * context)1400 angle::Result TextureD3D_2D::initMipmapImages(const gl::Context *context)
1401 {
1402     const GLuint baseLevel = mState.getEffectiveBaseLevel();
1403     const GLuint maxLevel  = mState.getMipmapMaxLevel();
1404     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
1405     // levels.
1406     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
1407     {
1408         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
1409                               std::max(getLevelZeroHeight() >> level, 1), 1);
1410 
1411         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
1412     }
1413     return angle::Result::Continue;
1414 }
1415 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)1416 angle::Result TextureD3D_2D::getRenderTarget(const gl::Context *context,
1417                                              const gl::ImageIndex &index,
1418                                              GLsizei samples,
1419                                              RenderTargetD3D **outRT)
1420 {
1421     ASSERT(!index.hasLayer());
1422 
1423     // ensure the underlying texture is created
1424     ANGLE_TRY(ensureRenderTarget(context));
1425     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
1426 
1427     return mTexStorage->getRenderTarget(context, index, samples, outRT);
1428 }
1429 
isValidLevel(int level) const1430 bool TextureD3D_2D::isValidLevel(int level) const
1431 {
1432     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
1433 }
1434 
isLevelComplete(int level) const1435 bool TextureD3D_2D::isLevelComplete(int level) const
1436 {
1437     if (isImmutable())
1438     {
1439         return true;
1440     }
1441 
1442     GLsizei width  = getLevelZeroWidth();
1443     GLsizei height = getLevelZeroHeight();
1444 
1445     if (width <= 0 || height <= 0)
1446     {
1447         return false;
1448     }
1449 
1450     // The base image level is complete if the width and height are positive
1451     if (level == static_cast<int>(getBaseLevel()))
1452     {
1453         return true;
1454     }
1455 
1456     ASSERT(level >= 0 && level <= static_cast<int>(mImageArray.size()) &&
1457            mImageArray[level] != nullptr);
1458     ImageD3D *image = mImageArray[level].get();
1459 
1460     if (image->getInternalFormat() != getBaseLevelInternalFormat())
1461     {
1462         return false;
1463     }
1464 
1465     if (image->getWidth() != std::max(1, width >> level))
1466     {
1467         return false;
1468     }
1469 
1470     if (image->getHeight() != std::max(1, height >> level))
1471     {
1472         return false;
1473     }
1474 
1475     return true;
1476 }
1477 
isImageComplete(const gl::ImageIndex & index) const1478 bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
1479 {
1480     return isLevelComplete(index.getLevelIndex());
1481 }
1482 
1483 // Constructs a native texture resource from the texture images
initializeStorage(const gl::Context * context,bool renderTarget)1484 angle::Result TextureD3D_2D::initializeStorage(const gl::Context *context, bool renderTarget)
1485 {
1486     // Only initialize the first time this texture is used as a render target or shader resource
1487     if (mTexStorage)
1488     {
1489         return angle::Result::Continue;
1490     }
1491 
1492     // do not attempt to create storage for nonexistant data
1493     if (!isLevelComplete(getBaseLevel()))
1494     {
1495         return angle::Result::Continue;
1496     }
1497 
1498     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
1499 
1500     TexStoragePointer storage(context);
1501     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
1502 
1503     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
1504     storage.release();
1505 
1506     ASSERT(mTexStorage);
1507 
1508     // flush image data to the storage
1509     ANGLE_TRY(updateStorage(context));
1510 
1511     return angle::Result::Continue;
1512 }
1513 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const1514 angle::Result TextureD3D_2D::createCompleteStorage(bool renderTarget,
1515                                                    TexStoragePointer *outStorage) const
1516 {
1517     GLsizei width         = getLevelZeroWidth();
1518     GLsizei height        = getLevelZeroHeight();
1519     GLenum internalFormat = getBaseLevelInternalFormat();
1520 
1521     ASSERT(width > 0 && height > 0);
1522 
1523     // use existing storage level count, when previously specified by TexStorage*D
1524     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1525 
1526     bool hintLevelZeroOnly = false;
1527     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1528     {
1529         // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use
1530         // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
1531         hintLevelZeroOnly = true;
1532         for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1533         {
1534             hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1535         }
1536     }
1537 
1538     // TODO(geofflang): Determine if the texture creation succeeded
1539     outStorage->reset(mRenderer->createTextureStorage2D(
1540         internalFormat, renderTarget, width, height, levels, mState.getLabel(), hintLevelZeroOnly));
1541 
1542     return angle::Result::Continue;
1543 }
1544 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)1545 angle::Result TextureD3D_2D::setCompleteTexStorage(const gl::Context *context,
1546                                                    TextureStorage *newCompleteTexStorage)
1547 {
1548     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
1549     {
1550         for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
1551         {
1552             ANGLE_TRY(
1553                 mImageArray[level]->setManagedSurface2D(context, newCompleteTexStorage, level));
1554         }
1555     }
1556 
1557     ANGLE_TRY(releaseTexStorage(context));
1558     mTexStorage = newCompleteTexStorage;
1559     mTexStorageObserverBinding.bind(mTexStorage);
1560 
1561     mDirtyImages = true;
1562 
1563     return angle::Result::Continue;
1564 }
1565 
updateStorage(const gl::Context * context)1566 angle::Result TextureD3D_2D::updateStorage(const gl::Context *context)
1567 {
1568     if (!mDirtyImages)
1569     {
1570         return angle::Result::Continue;
1571     }
1572 
1573     ASSERT(mTexStorage != nullptr);
1574     GLint storageLevels = mTexStorage->getLevelCount();
1575     for (int level = 0; level < storageLevels; level++)
1576     {
1577         if (mImageArray[level]->isDirty() && isLevelComplete(level))
1578         {
1579             ANGLE_TRY(updateStorageLevel(context, level));
1580         }
1581     }
1582 
1583     mDirtyImages = false;
1584     return angle::Result::Continue;
1585 }
1586 
updateStorageLevel(const gl::Context * context,int level)1587 angle::Result TextureD3D_2D::updateStorageLevel(const gl::Context *context, int level)
1588 {
1589     ASSERT(level <= static_cast<int>(mImageArray.size()) && mImageArray[level] != nullptr);
1590     ASSERT(isLevelComplete(level));
1591 
1592     if (mImageArray[level]->isDirty())
1593     {
1594         gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1595         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
1596         ANGLE_TRY(commitRegion(context, index, region));
1597     }
1598 
1599     return angle::Result::Continue;
1600 }
1601 
redefineImage(const gl::Context * context,size_t level,GLenum internalformat,const gl::Extents & size,bool forceRelease)1602 angle::Result TextureD3D_2D::redefineImage(const gl::Context *context,
1603                                            size_t level,
1604                                            GLenum internalformat,
1605                                            const gl::Extents &size,
1606                                            bool forceRelease)
1607 {
1608     ASSERT(size.depth == 1);
1609 
1610     // If there currently is a corresponding storage texture image, it has these parameters
1611     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
1612     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
1613     const GLenum storageFormat = getBaseLevelInternalFormat();
1614 
1615     mImageArray[level]->redefine(gl::TextureType::_2D, internalformat, size, forceRelease);
1616     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
1617 
1618     if (mTexStorage)
1619     {
1620         const size_t storageLevels = mTexStorage->getLevelCount();
1621 
1622         // If the storage was from an EGL image, copy it back into local images to preserve it
1623         // while orphaning
1624         if (level != 0 && mEGLImageTarget)
1625         {
1626             ANGLE_TRY(mImageArray[0]->copyFromTexStorage(context, gl::ImageIndex::Make2D(0),
1627                                                          mTexStorage));
1628         }
1629 
1630         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
1631             size.height != storageHeight || internalformat != storageFormat ||
1632             mEGLImageTarget)  // Discard mismatched storage
1633         {
1634             ANGLE_TRY(releaseTexStorage(context));
1635             markAllImagesDirty();
1636         }
1637     }
1638 
1639     // Can't be an EGL image target after being redefined
1640     mEGLImageTarget = false;
1641 
1642     return angle::Result::Continue;
1643 }
1644 
imageIterator() const1645 gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1646 {
1647     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1648 }
1649 
getImageIndex(GLint mip,GLint) const1650 gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1651 {
1652     // "layer" does not apply to 2D Textures.
1653     return gl::ImageIndex::Make2D(mip);
1654 }
1655 
isValidIndex(const gl::ImageIndex & index) const1656 bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1657 {
1658     return (mTexStorage && index.getType() == gl::TextureType::_2D && index.getLevelIndex() >= 0 &&
1659             index.getLevelIndex() < mTexStorage->getLevelCount());
1660 }
1661 
markAllImagesDirty()1662 void TextureD3D_2D::markAllImagesDirty()
1663 {
1664     for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1665     {
1666         mImageArray[i]->markDirty();
1667     }
1668     mDirtyImages = true;
1669 }
1670 
TextureD3D_Cube(const gl::TextureState & state,RendererD3D * renderer)1671 TextureD3D_Cube::TextureD3D_Cube(const gl::TextureState &state, RendererD3D *renderer)
1672     : TextureD3D(state, renderer)
1673 {
1674     for (auto &face : mImageArray)
1675     {
1676         for (auto &image : face)
1677         {
1678             image.reset(renderer->createImage());
1679         }
1680     }
1681 }
1682 
onDestroy(const gl::Context * context)1683 void TextureD3D_Cube::onDestroy(const gl::Context *context)
1684 {
1685     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
1686     // for some of their data. If TextureStorage is deleted before the Images, then their data will
1687     // be wastefully copied back from the GPU before we delete the Images.
1688     for (auto &face : mImageArray)
1689     {
1690         for (auto &image : face)
1691         {
1692             image.reset();
1693         }
1694     }
1695     return TextureD3D::onDestroy(context);
1696 }
1697 
~TextureD3D_Cube()1698 TextureD3D_Cube::~TextureD3D_Cube() {}
1699 
getImage(int level,int layer) const1700 ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
1701 {
1702     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1703     ASSERT(layer >= 0 && static_cast<size_t>(layer) < gl::kCubeFaceCount);
1704     return mImageArray[layer][level].get();
1705 }
1706 
getImage(const gl::ImageIndex & index) const1707 ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1708 {
1709     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1710     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1711     return mImageArray[index.cubeMapFaceIndex()][index.getLevelIndex()].get();
1712 }
1713 
getLayerCount(int level) const1714 GLsizei TextureD3D_Cube::getLayerCount(int level) const
1715 {
1716     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1717     return gl::kCubeFaceCount;
1718 }
1719 
getInternalFormat(GLint level,GLint layer) const1720 GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
1721 {
1722     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1723         return mImageArray[layer][level]->getInternalFormat();
1724     else
1725         return GL_NONE;
1726 }
1727 
isDepth(GLint level,GLint layer) const1728 bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
1729 {
1730     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
1731 }
1732 
isSRGB(GLint level,GLint layer) const1733 bool TextureD3D_Cube::isSRGB(GLint level, GLint layer) const
1734 {
1735     return gl::GetSizedInternalFormatInfo(getInternalFormat(level, layer)).colorEncoding == GL_SRGB;
1736 }
1737 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)1738 angle::Result TextureD3D_Cube::setEGLImageTarget(const gl::Context *context,
1739                                                  gl::TextureType type,
1740                                                  egl::Image *image)
1741 {
1742     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
1743     return angle::Result::Continue;
1744 }
1745 
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)1746 angle::Result TextureD3D_Cube::setImage(const gl::Context *context,
1747                                         const gl::ImageIndex &index,
1748                                         GLenum internalFormat,
1749                                         const gl::Extents &size,
1750                                         GLenum format,
1751                                         GLenum type,
1752                                         const gl::PixelUnpackState &unpack,
1753                                         gl::Buffer *unpackBuffer,
1754                                         const uint8_t *pixels)
1755 {
1756     ASSERT(size.depth == 1);
1757 
1758     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1759     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1760                             internalFormatInfo.sizedInternalFormat, size, false));
1761 
1762     return setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0);
1763 }
1764 
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)1765 angle::Result TextureD3D_Cube::setSubImage(const gl::Context *context,
1766                                            const gl::ImageIndex &index,
1767                                            const gl::Box &area,
1768                                            GLenum format,
1769                                            GLenum type,
1770                                            const gl::PixelUnpackState &unpack,
1771                                            gl::Buffer *unpackBuffer,
1772                                            const uint8_t *pixels)
1773 {
1774     ASSERT(area.depth == 1 && area.z == 0);
1775     return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer, pixels,
1776                                 0);
1777 }
1778 
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)1779 angle::Result TextureD3D_Cube::setCompressedImage(const gl::Context *context,
1780                                                   const gl::ImageIndex &index,
1781                                                   GLenum internalFormat,
1782                                                   const gl::Extents &size,
1783                                                   const gl::PixelUnpackState &unpack,
1784                                                   size_t imageSize,
1785                                                   const uint8_t *pixels)
1786 {
1787     ASSERT(size.depth == 1);
1788 
1789     // compressed formats don't have separate sized internal formats-- we can just use the
1790     // compressed format directly
1791     ANGLE_TRY(redefineImage(context, index.cubeMapFaceIndex(), index.getLevelIndex(),
1792                             internalFormat, size, false));
1793 
1794     return setCompressedImageImpl(context, index, unpack, pixels, 0);
1795 }
1796 
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)1797 angle::Result TextureD3D_Cube::setCompressedSubImage(const gl::Context *context,
1798                                                      const gl::ImageIndex &index,
1799                                                      const gl::Box &area,
1800                                                      GLenum format,
1801                                                      const gl::PixelUnpackState &unpack,
1802                                                      size_t imageSize,
1803                                                      const uint8_t *pixels)
1804 {
1805     ASSERT(area.depth == 1 && area.z == 0);
1806 
1807     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
1808     return commitRegion(context, index, area);
1809 }
1810 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)1811 angle::Result TextureD3D_Cube::copyImage(const gl::Context *context,
1812                                          const gl::ImageIndex &index,
1813                                          const gl::Rectangle &sourceArea,
1814                                          GLenum internalFormat,
1815                                          gl::Framebuffer *source)
1816 {
1817     GLint faceIndex = index.cubeMapFaceIndex();
1818     const gl::InternalFormat &internalFormatInfo =
1819         gl::GetInternalFormatInfo(internalFormat, GL_UNSIGNED_BYTE);
1820 
1821     gl::Extents size(sourceArea.width, sourceArea.height, 1);
1822     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1823                             internalFormatInfo.sizedInternalFormat, size, false));
1824 
1825     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1826 
1827     // Does the read area extend beyond the framebuffer?
1828     bool outside = sourceArea.x < 0 || sourceArea.y < 0 ||
1829                    sourceArea.x + sourceArea.width > fbSize.width ||
1830                    sourceArea.y + sourceArea.height > fbSize.height;
1831 
1832     // WebGL requires that pixels that would be outside the framebuffer are treated as zero values,
1833     // so clear the mip level to 0 prior to making the copy if any pixel would be sampled outside.
1834     // Same thing for robust resource init.
1835     if (outside && (context->isWebGL() || context->isRobustResourceInitEnabled()))
1836     {
1837         ANGLE_TRY(initializeContents(context, index));
1838     }
1839 
1840     gl::Rectangle clippedArea;
1841     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1842     {
1843         // Empty source area, nothing to do.
1844         return angle::Result::Continue;
1845     }
1846 
1847     gl::Offset destOffset(clippedArea.x - sourceArea.x, clippedArea.y - sourceArea.y, 0);
1848 
1849     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1850     // framebuffer in shaders, so we should use the non-rendering copy path.
1851     if (!canCreateRenderTargetForImage(index) ||
1852         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1853     {
1854         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1855             context, destOffset, clippedArea, source));
1856         mDirtyImages = true;
1857     }
1858     else
1859     {
1860         ANGLE_TRY(ensureRenderTarget(context));
1861 
1862         ASSERT(size.width == size.height);
1863 
1864         if (size.width > 0 && isValidFaceLevel(faceIndex, index.getLevelIndex()))
1865         {
1866             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1867             ANGLE_TRY(mRenderer->copyImageCube(context, source, clippedArea, internalFormat,
1868                                                destOffset, mTexStorage, index.getTarget(),
1869                                                index.getLevelIndex()));
1870         }
1871     }
1872 
1873     return angle::Result::Continue;
1874 }
1875 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)1876 angle::Result TextureD3D_Cube::copySubImage(const gl::Context *context,
1877                                             const gl::ImageIndex &index,
1878                                             const gl::Offset &destOffset,
1879                                             const gl::Rectangle &sourceArea,
1880                                             gl::Framebuffer *source)
1881 {
1882     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
1883     gl::Rectangle clippedArea;
1884     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height), &clippedArea))
1885     {
1886         return angle::Result::Continue;
1887     }
1888     const gl::Offset clippedOffset(destOffset.x + clippedArea.x - sourceArea.x,
1889                                    destOffset.y + clippedArea.y - sourceArea.y, 0);
1890 
1891     GLint faceIndex = index.cubeMapFaceIndex();
1892 
1893     // If the zero max LOD workaround is active, then we can't sample from individual layers of the
1894     // framebuffer in shaders, so we should use the non-rendering copy path.
1895     if (!canCreateRenderTargetForImage(index) ||
1896         mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
1897     {
1898         ANGLE_TRY(mImageArray[faceIndex][index.getLevelIndex()]->copyFromFramebuffer(
1899             context, clippedOffset, clippedArea, source));
1900         mDirtyImages = true;
1901     }
1902     else
1903     {
1904         ANGLE_TRY(ensureRenderTarget(context));
1905         if (isValidFaceLevel(faceIndex, index.getLevelIndex()))
1906         {
1907             ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1908             ANGLE_TRY(mRenderer->copyImageCube(
1909                 context, source, clippedArea, gl::GetUnsizedFormat(getBaseLevelInternalFormat()),
1910                 clippedOffset, mTexStorage, index.getTarget(), index.getLevelIndex()));
1911         }
1912     }
1913 
1914     return angle::Result::Continue;
1915 }
1916 
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)1917 angle::Result TextureD3D_Cube::copyTexture(const gl::Context *context,
1918                                            const gl::ImageIndex &index,
1919                                            GLenum internalFormat,
1920                                            GLenum type,
1921                                            GLint sourceLevel,
1922                                            bool unpackFlipY,
1923                                            bool unpackPremultiplyAlpha,
1924                                            bool unpackUnmultiplyAlpha,
1925                                            const gl::Texture *source)
1926 {
1927     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1928 
1929     gl::TextureTarget sourceTarget = NonCubeTextureTypeToTarget(source->getType());
1930 
1931     GLint faceIndex = index.cubeMapFaceIndex();
1932 
1933     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
1934     gl::Extents size(static_cast<int>(source->getWidth(sourceTarget, sourceLevel)),
1935                      static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
1936     ANGLE_TRY(redefineImage(context, faceIndex, index.getLevelIndex(),
1937                             internalFormatInfo.sizedInternalFormat, size, false));
1938 
1939     gl::Box sourceBox(0, 0, 0, size.width, size.height, 1);
1940     gl::Offset destOffset(0, 0, 0);
1941 
1942     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1943     {
1944 
1945         ANGLE_TRY(ensureRenderTarget(context));
1946         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1947         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1948 
1949         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
1950                                          sourceBox, internalFormatInfo.format,
1951                                          internalFormatInfo.type, destOffset, mTexStorage,
1952                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
1953                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1954     }
1955     else
1956     {
1957         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
1958         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
1959         ImageD3D *sourceImage           = nullptr;
1960         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
1961 
1962         ImageD3D *destImage = nullptr;
1963         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
1964 
1965         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
1966                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
1967 
1968         mDirtyImages = true;
1969 
1970         gl::Box destRegion(destOffset, size);
1971         ANGLE_TRY(commitRegion(context, index, destRegion));
1972     }
1973 
1974     return angle::Result::Continue;
1975 }
1976 
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)1977 angle::Result TextureD3D_Cube::copySubTexture(const gl::Context *context,
1978                                               const gl::ImageIndex &index,
1979                                               const gl::Offset &destOffset,
1980                                               GLint sourceLevel,
1981                                               const gl::Box &sourceBox,
1982                                               bool unpackFlipY,
1983                                               bool unpackPremultiplyAlpha,
1984                                               bool unpackUnmultiplyAlpha,
1985                                               const gl::Texture *source)
1986 {
1987     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
1988 
1989     GLint faceIndex = index.cubeMapFaceIndex();
1990 
1991     if (!isSRGB(index.getLevelIndex(), faceIndex) && canCreateRenderTargetForImage(index))
1992     {
1993         ANGLE_TRY(ensureRenderTarget(context));
1994         ASSERT(isValidFaceLevel(faceIndex, index.getLevelIndex()));
1995         ANGLE_TRY(updateStorageFaceLevel(context, faceIndex, index.getLevelIndex()));
1996 
1997         const gl::InternalFormat &internalFormatInfo =
1998             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex(), faceIndex));
1999         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2D,
2000                                          sourceBox, internalFormatInfo.format,
2001                                          internalFormatInfo.type, destOffset, mTexStorage,
2002                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2003                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2004     }
2005     else
2006     {
2007         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(sourceLevel);
2008         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2009         ImageD3D *sourceImage           = nullptr;
2010         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2011 
2012         ImageD3D *destImage = nullptr;
2013         ANGLE_TRY(getImageAndSyncFromStorage(context, index, &destImage));
2014 
2015         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2016                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2017 
2018         mDirtyImages = true;
2019 
2020         gl::Box destRegion(destOffset.x, destOffset.y, 0, sourceBox.width, sourceBox.height, 1);
2021         ANGLE_TRY(commitRegion(context, index, destRegion));
2022     }
2023 
2024     return angle::Result::Continue;
2025 }
2026 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2027 angle::Result TextureD3D_Cube::setStorage(const gl::Context *context,
2028                                           gl::TextureType type,
2029                                           size_t levels,
2030                                           GLenum internalFormat,
2031                                           const gl::Extents &size)
2032 {
2033     ASSERT(size.width == size.height);
2034     ASSERT(size.depth == 1);
2035 
2036     for (size_t level = 0; level < levels; level++)
2037     {
2038         GLsizei mipSize = std::max(1, size.width >> level);
2039         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2040         {
2041             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalFormat,
2042                                                     gl::Extents(mipSize, mipSize, 1), true);
2043         }
2044     }
2045 
2046     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2047     {
2048         for (size_t faceIndex = 0; faceIndex < gl::kCubeFaceCount; faceIndex++)
2049         {
2050             mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, GL_NONE,
2051                                                     gl::Extents(0, 0, 0), true);
2052         }
2053     }
2054 
2055     // TODO(geofflang): Verify storage creation had no errors
2056     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2057 
2058     TexStoragePointer storage(context);
2059     storage.reset(mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width,
2060                                                       static_cast<int>(levels), false,
2061                                                       mState.getLabel()));
2062 
2063     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2064     storage.release();
2065 
2066     ANGLE_TRY(updateStorage(context));
2067 
2068     mImmutable = true;
2069 
2070     return angle::Result::Continue;
2071 }
2072 
2073 // Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
isCubeComplete() const2074 bool TextureD3D_Cube::isCubeComplete() const
2075 {
2076     int baseWidth     = getBaseLevelWidth();
2077     int baseHeight    = getBaseLevelHeight();
2078     GLenum baseFormat = getBaseLevelInternalFormat();
2079 
2080     if (baseWidth <= 0 || baseWidth != baseHeight)
2081     {
2082         return false;
2083     }
2084 
2085     for (size_t faceIndex = 1; faceIndex < gl::kCubeFaceCount; faceIndex++)
2086     {
2087         const ImageD3D &faceBaseImage = *mImageArray[faceIndex][getBaseLevel()];
2088 
2089         if (faceBaseImage.getWidth() != baseWidth || faceBaseImage.getHeight() != baseHeight ||
2090             faceBaseImage.getInternalFormat() != baseFormat)
2091         {
2092             return false;
2093         }
2094     }
2095 
2096     return true;
2097 }
2098 
bindTexImage(const gl::Context * context,egl::Surface * surface)2099 angle::Result TextureD3D_Cube::bindTexImage(const gl::Context *context, egl::Surface *surface)
2100 {
2101     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2102     return angle::Result::Continue;
2103 }
2104 
releaseTexImage(const gl::Context * context)2105 angle::Result TextureD3D_Cube::releaseTexImage(const gl::Context *context)
2106 {
2107     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2108     return angle::Result::Continue;
2109 }
2110 
initMipmapImages(const gl::Context * context)2111 angle::Result TextureD3D_Cube::initMipmapImages(const gl::Context *context)
2112 {
2113     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2114     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2115     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2116     // levels.
2117     for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2118     {
2119         for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2120         {
2121             int faceLevelSize =
2122                 (std::max(mImageArray[faceIndex][baseLevel]->getWidth() >> (level - baseLevel), 1));
2123             ANGLE_TRY(redefineImage(context, faceIndex, level,
2124                                     mImageArray[faceIndex][baseLevel]->getInternalFormat(),
2125                                     gl::Extents(faceLevelSize, faceLevelSize, 1), false));
2126         }
2127     }
2128     return angle::Result::Continue;
2129 }
2130 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2131 angle::Result TextureD3D_Cube::getRenderTarget(const gl::Context *context,
2132                                                const gl::ImageIndex &index,
2133                                                GLsizei samples,
2134                                                RenderTargetD3D **outRT)
2135 {
2136     ASSERT(gl::IsCubeMapFaceTarget(index.getTarget()));
2137 
2138     // ensure the underlying texture is created
2139     ANGLE_TRY(ensureRenderTarget(context));
2140     ANGLE_TRY(updateStorageFaceLevel(context, index.cubeMapFaceIndex(), index.getLevelIndex()));
2141 
2142     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2143 }
2144 
initializeStorage(const gl::Context * context,bool renderTarget)2145 angle::Result TextureD3D_Cube::initializeStorage(const gl::Context *context, bool renderTarget)
2146 {
2147     // Only initialize the first time this texture is used as a render target or shader resource
2148     if (mTexStorage)
2149     {
2150         return angle::Result::Continue;
2151     }
2152 
2153     // do not attempt to create storage for nonexistant data
2154     if (!isFaceLevelComplete(0, getBaseLevel()))
2155     {
2156         return angle::Result::Continue;
2157     }
2158 
2159     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2160 
2161     TexStoragePointer storage(context);
2162     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2163 
2164     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2165     storage.release();
2166 
2167     ASSERT(mTexStorage);
2168 
2169     // flush image data to the storage
2170     ANGLE_TRY(updateStorage(context));
2171 
2172     return angle::Result::Continue;
2173 }
2174 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2175 angle::Result TextureD3D_Cube::createCompleteStorage(bool renderTarget,
2176                                                      TexStoragePointer *outStorage) const
2177 {
2178     GLsizei size = getLevelZeroWidth();
2179 
2180     ASSERT(size > 0);
2181 
2182     // use existing storage level count, when previously specified by TexStorage*D
2183     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
2184 
2185     bool hintLevelZeroOnly = false;
2186     if (mRenderer->getFeatures().zeroMaxLodWorkaround.enabled)
2187     {
2188         // If any of the CPU images (levels >= 1) are dirty, then the textureStorageEXT should use
2189         // the mipped texture to begin with. Otherwise, it should use the level-zero-only texture.
2190         hintLevelZeroOnly = true;
2191         for (int faceIndex = 0;
2192              faceIndex < static_cast<int>(gl::kCubeFaceCount) && hintLevelZeroOnly; faceIndex++)
2193         {
2194             for (int level = 1; level < levels && hintLevelZeroOnly; level++)
2195             {
2196                 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() &&
2197                                       isFaceLevelComplete(faceIndex, level));
2198             }
2199         }
2200     }
2201 
2202     // TODO (geofflang): detect if storage creation succeeded
2203     outStorage->reset(mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(),
2204                                                           renderTarget, size, levels,
2205                                                           hintLevelZeroOnly, mState.getLabel()));
2206 
2207     return angle::Result::Continue;
2208 }
2209 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2210 angle::Result TextureD3D_Cube::setCompleteTexStorage(const gl::Context *context,
2211                                                      TextureStorage *newCompleteTexStorage)
2212 {
2213     if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
2214     {
2215         for (int faceIndex = 0; faceIndex < static_cast<int>(gl::kCubeFaceCount); faceIndex++)
2216         {
2217             for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
2218             {
2219                 ANGLE_TRY(mImageArray[faceIndex][level]->setManagedSurfaceCube(
2220                     context, newCompleteTexStorage, faceIndex, level));
2221             }
2222         }
2223     }
2224 
2225     ANGLE_TRY(releaseTexStorage(context));
2226     mTexStorage = newCompleteTexStorage;
2227     mTexStorageObserverBinding.bind(mTexStorage);
2228 
2229     mDirtyImages = true;
2230     return angle::Result::Continue;
2231 }
2232 
updateStorage(const gl::Context * context)2233 angle::Result TextureD3D_Cube::updateStorage(const gl::Context *context)
2234 {
2235     if (!mDirtyImages)
2236     {
2237         return angle::Result::Continue;
2238     }
2239 
2240     ASSERT(mTexStorage != nullptr);
2241     GLint storageLevels = mTexStorage->getLevelCount();
2242     for (int face = 0; face < static_cast<int>(gl::kCubeFaceCount); face++)
2243     {
2244         for (int level = 0; level < storageLevels; level++)
2245         {
2246             if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
2247             {
2248                 ANGLE_TRY(updateStorageFaceLevel(context, face, level));
2249             }
2250         }
2251     }
2252 
2253     mDirtyImages = false;
2254     return angle::Result::Continue;
2255 }
2256 
isValidFaceLevel(int faceIndex,int level) const2257 bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
2258 {
2259     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2260 }
2261 
isFaceLevelComplete(int faceIndex,int level) const2262 bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
2263 {
2264     if (getBaseLevel() >= gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2265     {
2266         return false;
2267     }
2268     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2269            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2270            mImageArray[faceIndex][level] != nullptr);
2271 
2272     if (isImmutable())
2273     {
2274         return true;
2275     }
2276 
2277     int levelZeroSize = getLevelZeroWidth();
2278 
2279     if (levelZeroSize <= 0)
2280     {
2281         return false;
2282     }
2283 
2284     // Check that non-zero levels are consistent with the base level.
2285     const ImageD3D *faceLevelImage = mImageArray[faceIndex][level].get();
2286 
2287     if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
2288     {
2289         return false;
2290     }
2291 
2292     if (faceLevelImage->getWidth() != std::max(1, levelZeroSize >> level))
2293     {
2294         return false;
2295     }
2296 
2297     return true;
2298 }
2299 
isImageComplete(const gl::ImageIndex & index) const2300 bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
2301 {
2302     return isFaceLevelComplete(index.cubeMapFaceIndex(), index.getLevelIndex());
2303 }
2304 
updateStorageFaceLevel(const gl::Context * context,int faceIndex,int level)2305 angle::Result TextureD3D_Cube::updateStorageFaceLevel(const gl::Context *context,
2306                                                       int faceIndex,
2307                                                       int level)
2308 {
2309     ASSERT(level >= 0 && static_cast<size_t>(faceIndex) < gl::kCubeFaceCount &&
2310            level < static_cast<int>(mImageArray[faceIndex].size()) &&
2311            mImageArray[faceIndex][level] != nullptr);
2312     ImageD3D *image = mImageArray[faceIndex][level].get();
2313 
2314     if (image->isDirty())
2315     {
2316         gl::TextureTarget faceTarget = gl::CubeFaceIndexToTextureTarget(faceIndex);
2317         gl::ImageIndex index         = gl::ImageIndex::MakeCubeMapFace(faceTarget, level);
2318         gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
2319         ANGLE_TRY(commitRegion(context, index, region));
2320     }
2321 
2322     return angle::Result::Continue;
2323 }
2324 
redefineImage(const gl::Context * context,int faceIndex,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2325 angle::Result TextureD3D_Cube::redefineImage(const gl::Context *context,
2326                                              int faceIndex,
2327                                              GLint level,
2328                                              GLenum internalformat,
2329                                              const gl::Extents &size,
2330                                              bool forceRelease)
2331 {
2332     // If there currently is a corresponding storage texture image, it has these parameters
2333     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
2334     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
2335     const GLenum storageFormat = getBaseLevelInternalFormat();
2336 
2337     mImageArray[faceIndex][level]->redefine(gl::TextureType::CubeMap, internalformat, size,
2338                                             forceRelease);
2339     mDirtyImages = mDirtyImages || mImageArray[faceIndex][level]->isDirty();
2340 
2341     if (mTexStorage)
2342     {
2343         const int storageLevels = mTexStorage->getLevelCount();
2344 
2345         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
2346             size.height != storageHeight ||
2347             internalformat != storageFormat)  // Discard mismatched storage
2348         {
2349             markAllImagesDirty();
2350             ANGLE_TRY(releaseTexStorage(context));
2351         }
2352     }
2353 
2354     return angle::Result::Continue;
2355 }
2356 
imageIterator() const2357 gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
2358 {
2359     return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
2360 }
2361 
getImageIndex(GLint mip,GLint layer) const2362 gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
2363 {
2364     // The "layer" of the image index corresponds to the cube face
2365     return gl::ImageIndex::MakeCubeMapFace(gl::CubeFaceIndexToTextureTarget(layer), mip);
2366 }
2367 
isValidIndex(const gl::ImageIndex & index) const2368 bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
2369 {
2370     return (mTexStorage && index.getType() == gl::TextureType::CubeMap &&
2371             gl::IsCubeMapFaceTarget(index.getTarget()) && index.getLevelIndex() >= 0 &&
2372             index.getLevelIndex() < mTexStorage->getLevelCount());
2373 }
2374 
markAllImagesDirty()2375 void TextureD3D_Cube::markAllImagesDirty()
2376 {
2377     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
2378     {
2379         for (size_t dirtyFace = 0; dirtyFace < gl::kCubeFaceCount; dirtyFace++)
2380         {
2381             mImageArray[dirtyFace][dirtyLevel]->markDirty();
2382         }
2383     }
2384     mDirtyImages = true;
2385 }
2386 
TextureD3D_3D(const gl::TextureState & state,RendererD3D * renderer)2387 TextureD3D_3D::TextureD3D_3D(const gl::TextureState &state, RendererD3D *renderer)
2388     : TextureD3D(state, renderer)
2389 {
2390     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
2391     {
2392         mImageArray[i].reset(renderer->createImage());
2393     }
2394 }
2395 
onDestroy(const gl::Context * context)2396 void TextureD3D_3D::onDestroy(const gl::Context *context)
2397 {
2398     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
2399     // for some of their data. If TextureStorage is deleted before the Images, then their data will
2400     // be wastefully copied back from the GPU before we delete the Images.
2401     for (auto &image : mImageArray)
2402     {
2403         image.reset();
2404     }
2405     return TextureD3D::onDestroy(context);
2406 }
2407 
~TextureD3D_3D()2408 TextureD3D_3D::~TextureD3D_3D() {}
2409 
getImage(int level,int layer) const2410 ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
2411 {
2412     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2413     ASSERT(layer == 0);
2414     return mImageArray[level].get();
2415 }
2416 
getImage(const gl::ImageIndex & index) const2417 ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
2418 {
2419     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2420     ASSERT(!index.hasLayer());
2421     ASSERT(index.getType() == gl::TextureType::_3D);
2422     return mImageArray[index.getLevelIndex()].get();
2423 }
2424 
getLayerCount(int level) const2425 GLsizei TextureD3D_3D::getLayerCount(int level) const
2426 {
2427     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2428     return 1;
2429 }
2430 
getWidth(GLint level) const2431 GLsizei TextureD3D_3D::getWidth(GLint level) const
2432 {
2433     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2434         return mImageArray[level]->getWidth();
2435     else
2436         return 0;
2437 }
2438 
getHeight(GLint level) const2439 GLsizei TextureD3D_3D::getHeight(GLint level) const
2440 {
2441     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2442         return mImageArray[level]->getHeight();
2443     else
2444         return 0;
2445 }
2446 
getDepth(GLint level) const2447 GLsizei TextureD3D_3D::getDepth(GLint level) const
2448 {
2449     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2450         return mImageArray[level]->getDepth();
2451     else
2452         return 0;
2453 }
2454 
getInternalFormat(GLint level) const2455 GLenum TextureD3D_3D::getInternalFormat(GLint level) const
2456 {
2457     if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
2458         return mImageArray[level]->getInternalFormat();
2459     else
2460         return GL_NONE;
2461 }
2462 
isDepth(GLint level) const2463 bool TextureD3D_3D::isDepth(GLint level) const
2464 {
2465     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
2466 }
2467 
isSRGB(GLint level) const2468 bool TextureD3D_3D::isSRGB(GLint level) const
2469 {
2470     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
2471 }
2472 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)2473 angle::Result TextureD3D_3D::setEGLImageTarget(const gl::Context *context,
2474                                                gl::TextureType type,
2475                                                egl::Image *image)
2476 {
2477     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2478     return angle::Result::Continue;
2479 }
2480 
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)2481 angle::Result TextureD3D_3D::setImage(const gl::Context *context,
2482                                       const gl::ImageIndex &index,
2483                                       GLenum internalFormat,
2484                                       const gl::Extents &size,
2485                                       GLenum format,
2486                                       GLenum type,
2487                                       const gl::PixelUnpackState &unpack,
2488                                       gl::Buffer *unpackBuffer,
2489                                       const uint8_t *pixels)
2490 {
2491     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2492     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2493 
2494     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2495                             size, false));
2496 
2497     bool fastUnpacked = false;
2498 
2499     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2500     if (isFastUnpackable(unpackBuffer, unpack, internalFormatInfo.sizedInternalFormat) &&
2501         !size.empty() && isLevelComplete(index.getLevelIndex()))
2502     {
2503         // Will try to create RT storage if it does not exist
2504         RenderTargetD3D *destRenderTarget = nullptr;
2505         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2506 
2507         gl::Box destArea(0, 0, 0, getWidth(index.getLevelIndex()), getHeight(index.getLevelIndex()),
2508                          getDepth(index.getLevelIndex()));
2509 
2510         ANGLE_TRY(fastUnpackPixels(context, unpack, unpackBuffer, pixels, destArea,
2511                                    internalFormatInfo.sizedInternalFormat, type, destRenderTarget));
2512 
2513         // Ensure we don't overwrite our newly initialized data
2514         mImageArray[index.getLevelIndex()]->markClean();
2515 
2516         fastUnpacked = true;
2517     }
2518 
2519     if (!fastUnpacked)
2520     {
2521         ANGLE_TRY(setImageImpl(context, index, type, unpack, unpackBuffer, pixels, 0));
2522     }
2523 
2524     return angle::Result::Continue;
2525 }
2526 
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)2527 angle::Result TextureD3D_3D::setSubImage(const gl::Context *context,
2528                                          const gl::ImageIndex &index,
2529                                          const gl::Box &area,
2530                                          GLenum format,
2531                                          GLenum type,
2532                                          const gl::PixelUnpackState &unpack,
2533                                          gl::Buffer *unpackBuffer,
2534                                          const uint8_t *pixels)
2535 {
2536     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2537 
2538     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
2539     GLenum mipFormat = getInternalFormat(index.getLevelIndex());
2540     if (isFastUnpackable(unpackBuffer, unpack, mipFormat) && isLevelComplete(index.getLevelIndex()))
2541     {
2542         RenderTargetD3D *destRenderTarget = nullptr;
2543         ANGLE_TRY(getRenderTarget(context, index, getRenderToTextureSamples(), &destRenderTarget));
2544         ASSERT(!mImageArray[index.getLevelIndex()]->isDirty());
2545 
2546         return fastUnpackPixels(context, unpack, unpackBuffer, pixels, area, mipFormat, type,
2547                                 destRenderTarget);
2548     }
2549     else
2550     {
2551         return TextureD3D::subImage(context, index, area, format, type, unpack, unpackBuffer,
2552                                     pixels, 0);
2553     }
2554 }
2555 
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)2556 angle::Result TextureD3D_3D::setCompressedImage(const gl::Context *context,
2557                                                 const gl::ImageIndex &index,
2558                                                 GLenum internalFormat,
2559                                                 const gl::Extents &size,
2560                                                 const gl::PixelUnpackState &unpack,
2561                                                 size_t imageSize,
2562                                                 const uint8_t *pixels)
2563 {
2564     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2565 
2566     // compressed formats don't have separate sized internal formats-- we can just use the
2567     // compressed format directly
2568     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
2569 
2570     return setCompressedImageImpl(context, index, unpack, pixels, 0);
2571 }
2572 
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)2573 angle::Result TextureD3D_3D::setCompressedSubImage(const gl::Context *context,
2574                                                    const gl::ImageIndex &index,
2575                                                    const gl::Box &area,
2576                                                    GLenum format,
2577                                                    const gl::PixelUnpackState &unpack,
2578                                                    size_t imageSize,
2579                                                    const uint8_t *pixels)
2580 {
2581     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2582 
2583     ANGLE_TRY(TextureD3D::subImageCompressed(context, index, area, format, unpack, pixels, 0));
2584     return commitRegion(context, index, area);
2585 }
2586 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)2587 angle::Result TextureD3D_3D::copyImage(const gl::Context *context,
2588                                        const gl::ImageIndex &index,
2589                                        const gl::Rectangle &sourceArea,
2590                                        GLenum internalFormat,
2591                                        gl::Framebuffer *source)
2592 {
2593     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2594     return angle::Result::Continue;
2595 }
2596 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)2597 angle::Result TextureD3D_3D::copySubImage(const gl::Context *context,
2598                                           const gl::ImageIndex &index,
2599                                           const gl::Offset &destOffset,
2600                                           const gl::Rectangle &sourceArea,
2601                                           gl::Framebuffer *source)
2602 {
2603     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2604 
2605     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
2606     gl::Rectangle clippedSourceArea;
2607     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
2608                        &clippedSourceArea))
2609     {
2610         return angle::Result::Continue;
2611     }
2612     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
2613                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
2614                                        destOffset.z);
2615 
2616     // Currently, copying directly to the storage is not possible because it's not possible to
2617     // create an SRV from a single layer of a 3D texture.  Instead, make sure the image is up to
2618     // date before the copy and then copy back to the storage afterwards if needed.
2619     // TODO: Investigate 3D blits in D3D11.
2620 
2621     bool syncTexStorage = mTexStorage && isLevelComplete(index.getLevelIndex());
2622     if (syncTexStorage)
2623     {
2624         ANGLE_TRY(
2625             mImageArray[index.getLevelIndex()]->copyFromTexStorage(context, index, mTexStorage));
2626     }
2627     ANGLE_TRY(mImageArray[index.getLevelIndex()]->copyFromFramebuffer(context, clippedDestOffset,
2628                                                                       clippedSourceArea, source));
2629     mDirtyImages = true;
2630 
2631     if (syncTexStorage)
2632     {
2633         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2634     }
2635 
2636     return angle::Result::Continue;
2637 }
2638 
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)2639 angle::Result TextureD3D_3D::copyTexture(const gl::Context *context,
2640                                          const gl::ImageIndex &index,
2641                                          GLenum internalFormat,
2642                                          GLenum type,
2643                                          GLint sourceLevel,
2644                                          bool unpackFlipY,
2645                                          bool unpackPremultiplyAlpha,
2646                                          bool unpackUnmultiplyAlpha,
2647                                          const gl::Texture *source)
2648 {
2649     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2650 
2651     gl::TextureType sourceType = source->getType();
2652 
2653     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
2654     gl::Extents size(
2655         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2656         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
2657         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
2658 
2659     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
2660                             size, false));
2661 
2662     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
2663     gl::Offset destOffset(0, 0, 0);
2664     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2665 
2666     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2667     {
2668         ANGLE_TRY(ensureRenderTarget(context));
2669         ASSERT(isValidLevel(index.getLevelIndex()));
2670         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2671 
2672         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2673                                          sourceBox, internalFormatInfo.format,
2674                                          internalFormatInfo.type, destOffset, mTexStorage,
2675                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2676                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2677     }
2678     else
2679     {
2680         gl::ImageIndex sourceIndex = gl::ImageIndex::Make3D(sourceLevel);
2681         ImageD3D *sourceImage      = nullptr;
2682         ImageD3D *destImage        = nullptr;
2683         TextureD3D *sourceD3D      = GetImplAs<TextureD3D>(source);
2684 
2685         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2686         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceIndex, &sourceImage));
2687 
2688         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2689                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2690 
2691         mDirtyImages = true;
2692 
2693         gl::Box destRegion(0, 0, 0, sourceBox.width, sourceBox.height, sourceBox.depth);
2694         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2695     }
2696 
2697     return angle::Result::Continue;
2698 }
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)2699 angle::Result TextureD3D_3D::copySubTexture(const gl::Context *context,
2700                                             const gl::ImageIndex &index,
2701                                             const gl::Offset &destOffset,
2702                                             GLint sourceLevel,
2703                                             const gl::Box &sourceBox,
2704                                             bool unpackFlipY,
2705                                             bool unpackPremultiplyAlpha,
2706                                             bool unpackUnmultiplyAlpha,
2707                                             const gl::Texture *source)
2708 {
2709     ASSERT(index.getTarget() == gl::TextureTarget::_3D);
2710 
2711     gl::ImageIndex destIndex = gl::ImageIndex::Make3D(static_cast<GLint>(index.getLevelIndex()));
2712 
2713     if (!isSRGB(index.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
2714     {
2715         ANGLE_TRY(ensureRenderTarget(context));
2716         ASSERT(isValidLevel(index.getLevelIndex()));
2717         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2718 
2719         const gl::InternalFormat &internalFormatInfo =
2720             gl::GetSizedInternalFormatInfo(getInternalFormat(index.getLevelIndex()));
2721         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_3D,
2722                                          sourceBox, internalFormatInfo.format,
2723                                          internalFormatInfo.type, destOffset, mTexStorage,
2724                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
2725                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2726     }
2727     else
2728     {
2729         gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make3D(sourceLevel);
2730         TextureD3D *sourceD3D           = GetImplAs<TextureD3D>(source);
2731         ImageD3D *sourceImage           = nullptr;
2732         ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, sourceImageIndex, &sourceImage));
2733 
2734         ImageD3D *destImage = nullptr;
2735         ANGLE_TRY(getImageAndSyncFromStorage(context, destIndex, &destImage));
2736 
2737         ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, sourceBox, destOffset,
2738                                        unpackFlipY, unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
2739 
2740         mDirtyImages = true;
2741 
2742         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
2743                            sourceBox.height, sourceBox.depth);
2744         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
2745     }
2746 
2747     return angle::Result::Continue;
2748 }
2749 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)2750 angle::Result TextureD3D_3D::setStorage(const gl::Context *context,
2751                                         gl::TextureType type,
2752                                         size_t levels,
2753                                         GLenum internalFormat,
2754                                         const gl::Extents &size)
2755 {
2756     ASSERT(type == gl::TextureType::_3D);
2757 
2758     for (size_t level = 0; level < levels; level++)
2759     {
2760         gl::Extents levelSize(std::max(1, size.width >> level), std::max(1, size.height >> level),
2761                               std::max(1, size.depth >> level));
2762         mImageArray[level]->redefine(gl::TextureType::_3D, internalFormat, levelSize, true);
2763     }
2764 
2765     for (size_t level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2766     {
2767         mImageArray[level]->redefine(gl::TextureType::_3D, GL_NONE, gl::Extents(0, 0, 0), true);
2768     }
2769 
2770     // TODO(geofflang): Verify storage creation had no errors
2771     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
2772     TexStoragePointer storage(context);
2773     storage.reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width,
2774                                                     size.height, size.depth,
2775                                                     static_cast<int>(levels), mState.getLabel()));
2776 
2777     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2778     storage.release();
2779 
2780     ANGLE_TRY(updateStorage(context));
2781 
2782     mImmutable = true;
2783 
2784     return angle::Result::Continue;
2785 }
2786 
bindTexImage(const gl::Context * context,egl::Surface * surface)2787 angle::Result TextureD3D_3D::bindTexImage(const gl::Context *context, egl::Surface *surface)
2788 {
2789     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2790     return angle::Result::Continue;
2791 }
2792 
releaseTexImage(const gl::Context * context)2793 angle::Result TextureD3D_3D::releaseTexImage(const gl::Context *context)
2794 {
2795     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
2796     return angle::Result::Continue;
2797 }
2798 
initMipmapImages(const gl::Context * context)2799 angle::Result TextureD3D_3D::initMipmapImages(const gl::Context *context)
2800 {
2801     const GLuint baseLevel = mState.getEffectiveBaseLevel();
2802     const GLuint maxLevel  = mState.getMipmapMaxLevel();
2803     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
2804     // levels.
2805     for (GLuint level = baseLevel + 1; level <= maxLevel; level++)
2806     {
2807         gl::Extents levelSize(std::max(getLevelZeroWidth() >> level, 1),
2808                               std::max(getLevelZeroHeight() >> level, 1),
2809                               std::max(getLevelZeroDepth() >> level, 1));
2810         ANGLE_TRY(redefineImage(context, level, getBaseLevelInternalFormat(), levelSize, false));
2811     }
2812 
2813     return angle::Result::Continue;
2814 }
2815 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)2816 angle::Result TextureD3D_3D::getRenderTarget(const gl::Context *context,
2817                                              const gl::ImageIndex &index,
2818                                              GLsizei samples,
2819                                              RenderTargetD3D **outRT)
2820 {
2821     // ensure the underlying texture is created
2822     ANGLE_TRY(ensureRenderTarget(context));
2823 
2824     if (index.hasLayer())
2825     {
2826         ANGLE_TRY(updateStorage(context));
2827     }
2828     else
2829     {
2830         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
2831     }
2832 
2833     return mTexStorage->getRenderTarget(context, index, samples, outRT);
2834 }
2835 
initializeStorage(const gl::Context * context,bool renderTarget)2836 angle::Result TextureD3D_3D::initializeStorage(const gl::Context *context, bool renderTarget)
2837 {
2838     // Only initialize the first time this texture is used as a render target or shader resource
2839     if (mTexStorage)
2840     {
2841         return angle::Result::Continue;
2842     }
2843 
2844     // do not attempt to create storage for nonexistant data
2845     if (!isLevelComplete(getBaseLevel()))
2846     {
2847         return angle::Result::Continue;
2848     }
2849 
2850     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
2851 
2852     TexStoragePointer storage(context);
2853     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
2854 
2855     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
2856     storage.release();
2857 
2858     ASSERT(mTexStorage);
2859 
2860     // flush image data to the storage
2861     ANGLE_TRY(updateStorage(context));
2862 
2863     return angle::Result::Continue;
2864 }
2865 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const2866 angle::Result TextureD3D_3D::createCompleteStorage(bool renderTarget,
2867                                                    TexStoragePointer *outStorage) const
2868 {
2869     GLsizei width         = getLevelZeroWidth();
2870     GLsizei height        = getLevelZeroHeight();
2871     GLsizei depth         = getLevelZeroDepth();
2872     GLenum internalFormat = getBaseLevelInternalFormat();
2873 
2874     ASSERT(width > 0 && height > 0 && depth > 0);
2875 
2876     // use existing storage level count, when previously specified by TexStorage*D
2877     GLint levels =
2878         (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2879 
2880     // TODO: Verify creation of the storage succeeded
2881     outStorage->reset(mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height,
2882                                                         depth, levels, mState.getLabel()));
2883 
2884     return angle::Result::Continue;
2885 }
2886 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)2887 angle::Result TextureD3D_3D::setCompleteTexStorage(const gl::Context *context,
2888                                                    TextureStorage *newCompleteTexStorage)
2889 {
2890     ANGLE_TRY(releaseTexStorage(context));
2891     mTexStorage = newCompleteTexStorage;
2892     mTexStorageObserverBinding.bind(mTexStorage);
2893     mDirtyImages = true;
2894 
2895     // We do not support managed 3D storage, as that is D3D9/ES2-only
2896     ASSERT(!mTexStorage->isManaged());
2897 
2898     return angle::Result::Continue;
2899 }
2900 
updateStorage(const gl::Context * context)2901 angle::Result TextureD3D_3D::updateStorage(const gl::Context *context)
2902 {
2903     if (!mDirtyImages)
2904     {
2905         return angle::Result::Continue;
2906     }
2907 
2908     ASSERT(mTexStorage != nullptr);
2909     GLint storageLevels = mTexStorage->getLevelCount();
2910     for (int level = 0; level < storageLevels; level++)
2911     {
2912         if (mImageArray[level]->isDirty() && isLevelComplete(level))
2913         {
2914             ANGLE_TRY(updateStorageLevel(context, level));
2915         }
2916     }
2917 
2918     mDirtyImages = false;
2919     return angle::Result::Continue;
2920 }
2921 
isValidLevel(int level) const2922 bool TextureD3D_3D::isValidLevel(int level) const
2923 {
2924     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2925 }
2926 
isLevelComplete(int level) const2927 bool TextureD3D_3D::isLevelComplete(int level) const
2928 {
2929     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2930            mImageArray[level] != nullptr);
2931 
2932     if (isImmutable())
2933     {
2934         return true;
2935     }
2936 
2937     GLsizei width  = getLevelZeroWidth();
2938     GLsizei height = getLevelZeroHeight();
2939     GLsizei depth  = getLevelZeroDepth();
2940 
2941     if (width <= 0 || height <= 0 || depth <= 0)
2942     {
2943         return false;
2944     }
2945 
2946     if (level == static_cast<int>(getBaseLevel()))
2947     {
2948         return true;
2949     }
2950 
2951     ImageD3D *levelImage = mImageArray[level].get();
2952 
2953     if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2954     {
2955         return false;
2956     }
2957 
2958     if (levelImage->getWidth() != std::max(1, width >> level))
2959     {
2960         return false;
2961     }
2962 
2963     if (levelImage->getHeight() != std::max(1, height >> level))
2964     {
2965         return false;
2966     }
2967 
2968     if (levelImage->getDepth() != std::max(1, depth >> level))
2969     {
2970         return false;
2971     }
2972 
2973     return true;
2974 }
2975 
isImageComplete(const gl::ImageIndex & index) const2976 bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2977 {
2978     return isLevelComplete(index.getLevelIndex());
2979 }
2980 
updateStorageLevel(const gl::Context * context,int level)2981 angle::Result TextureD3D_3D::updateStorageLevel(const gl::Context *context, int level)
2982 {
2983     ASSERT(level >= 0 && level < static_cast<int>(mImageArray.size()) &&
2984            mImageArray[level] != nullptr);
2985     ASSERT(isLevelComplete(level));
2986 
2987     if (mImageArray[level]->isDirty())
2988     {
2989         gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2990         gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
2991         ANGLE_TRY(commitRegion(context, index, region));
2992     }
2993 
2994     return angle::Result::Continue;
2995 }
2996 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)2997 angle::Result TextureD3D_3D::redefineImage(const gl::Context *context,
2998                                            GLint level,
2999                                            GLenum internalformat,
3000                                            const gl::Extents &size,
3001                                            bool forceRelease)
3002 {
3003     // If there currently is a corresponding storage texture image, it has these parameters
3004     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
3005     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
3006     const int storageDepth     = std::max(1, getLevelZeroDepth() >> level);
3007     const GLenum storageFormat = getBaseLevelInternalFormat();
3008 
3009     mImageArray[level]->redefine(gl::TextureType::_3D, internalformat, size, forceRelease);
3010     mDirtyImages = mDirtyImages || mImageArray[level]->isDirty();
3011 
3012     if (mTexStorage)
3013     {
3014         const int storageLevels = mTexStorage->getLevelCount();
3015 
3016         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3017             size.height != storageHeight || size.depth != storageDepth ||
3018             internalformat != storageFormat)  // Discard mismatched storage
3019         {
3020             markAllImagesDirty();
3021             ANGLE_TRY(releaseTexStorage(context));
3022         }
3023     }
3024 
3025     return angle::Result::Continue;
3026 }
3027 
imageIterator() const3028 gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
3029 {
3030     return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
3031                                           gl::ImageIndex::kEntireLevel,
3032                                           gl::ImageIndex::kEntireLevel);
3033 }
3034 
getImageIndex(GLint mip,GLint) const3035 gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
3036 {
3037     // The "layer" here does not apply to 3D images. We use one Image per mip.
3038     return gl::ImageIndex::Make3D(mip);
3039 }
3040 
isValidIndex(const gl::ImageIndex & index) const3041 bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
3042 {
3043     return (mTexStorage && index.getType() == gl::TextureType::_3D && index.getLevelIndex() >= 0 &&
3044             index.getLevelIndex() < mTexStorage->getLevelCount());
3045 }
3046 
markAllImagesDirty()3047 void TextureD3D_3D::markAllImagesDirty()
3048 {
3049     for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
3050     {
3051         mImageArray[i]->markDirty();
3052     }
3053     mDirtyImages = true;
3054 }
3055 
getLevelZeroDepth() const3056 GLint TextureD3D_3D::getLevelZeroDepth() const
3057 {
3058     ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelDepth())) > getBaseLevel());
3059     return getBaseLevelDepth() << getBaseLevel();
3060 }
3061 
TextureD3D_2DArray(const gl::TextureState & state,RendererD3D * renderer)3062 TextureD3D_2DArray::TextureD3D_2DArray(const gl::TextureState &state, RendererD3D *renderer)
3063     : TextureD3D(state, renderer)
3064 {
3065     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3066     {
3067         mLayerCounts[level] = 0;
3068         mImageArray[level]  = nullptr;
3069     }
3070 }
3071 
onDestroy(const gl::Context * context)3072 void TextureD3D_2DArray::onDestroy(const gl::Context *context)
3073 {
3074     // Delete the Images before the TextureStorage. Images might be relying on the TextureStorage
3075     // for some of their data. If TextureStorage is deleted before the Images, then their data will
3076     // be wastefully copied back from the GPU before we delete the Images.
3077     deleteImages();
3078     return TextureD3D::onDestroy(context);
3079 }
3080 
~TextureD3D_2DArray()3081 TextureD3D_2DArray::~TextureD3D_2DArray() {}
3082 
getImage(int level,int layer) const3083 ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
3084 {
3085     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3086     ASSERT((layer == 0 && mLayerCounts[level] == 0) || layer < mLayerCounts[level]);
3087     return (mImageArray[level] ? mImageArray[level][layer] : nullptr);
3088 }
3089 
getImage(const gl::ImageIndex & index) const3090 ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
3091 {
3092     ASSERT(index.getLevelIndex() < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3093     ASSERT(index.hasLayer());
3094     ASSERT((index.getLayerIndex() == 0 && mLayerCounts[index.getLevelIndex()] == 0) ||
3095            index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]);
3096     ASSERT(index.getType() == gl::TextureType::_2DArray);
3097     return (mImageArray[index.getLevelIndex()]
3098                 ? mImageArray[index.getLevelIndex()][index.getLayerIndex()]
3099                 : nullptr);
3100 }
3101 
getLayerCount(int level) const3102 GLsizei TextureD3D_2DArray::getLayerCount(int level) const
3103 {
3104     ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
3105     return mLayerCounts[level];
3106 }
3107 
getWidth(GLint level) const3108 GLsizei TextureD3D_2DArray::getWidth(GLint level) const
3109 {
3110     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3111                ? mImageArray[level][0]->getWidth()
3112                : 0;
3113 }
3114 
getHeight(GLint level) const3115 GLsizei TextureD3D_2DArray::getHeight(GLint level) const
3116 {
3117     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3118                ? mImageArray[level][0]->getHeight()
3119                : 0;
3120 }
3121 
getInternalFormat(GLint level) const3122 GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
3123 {
3124     return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0)
3125                ? mImageArray[level][0]->getInternalFormat()
3126                : GL_NONE;
3127 }
3128 
isDepth(GLint level) const3129 bool TextureD3D_2DArray::isDepth(GLint level) const
3130 {
3131     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
3132 }
3133 
isSRGB(GLint level) const3134 bool TextureD3D_2DArray::isSRGB(GLint level) const
3135 {
3136     return gl::GetSizedInternalFormatInfo(getInternalFormat(level)).colorEncoding == GL_SRGB;
3137 }
3138 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3139 angle::Result TextureD3D_2DArray::setEGLImageTarget(const gl::Context *context,
3140                                                     gl::TextureType type,
3141                                                     egl::Image *image)
3142 {
3143     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3144     return angle::Result::Continue;
3145 }
3146 
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)3147 angle::Result TextureD3D_2DArray::setImage(const gl::Context *context,
3148                                            const gl::ImageIndex &index,
3149                                            GLenum internalFormat,
3150                                            const gl::Extents &size,
3151                                            GLenum format,
3152                                            GLenum type,
3153                                            const gl::PixelUnpackState &unpack,
3154                                            gl::Buffer *unpackBuffer,
3155                                            const uint8_t *pixels)
3156 {
3157     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3158 
3159     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3160 
3161     ANGLE_TRY(
3162         redefineImage(context, index.getLevelIndex(), formatInfo.sizedInternalFormat, size, false));
3163 
3164     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3165 
3166     GLuint inputDepthPitch = 0;
3167     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3168                                         type, size.width, size.height, unpack.alignment,
3169                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3170 
3171     for (int i = 0; i < size.depth; i++)
3172     {
3173         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3174         gl::ImageIndex layerIndex   = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3175         ANGLE_TRY(
3176             setImageImpl(context, layerIndex, type, unpack, unpackBuffer, pixels, layerOffset));
3177     }
3178 
3179     return angle::Result::Continue;
3180 }
3181 
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)3182 angle::Result TextureD3D_2DArray::setSubImage(const gl::Context *context,
3183                                               const gl::ImageIndex &index,
3184                                               const gl::Box &area,
3185                                               GLenum format,
3186                                               GLenum type,
3187                                               const gl::PixelUnpackState &unpack,
3188                                               gl::Buffer *unpackBuffer,
3189                                               const uint8_t *pixels)
3190 {
3191     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3192 
3193     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3194     const gl::InternalFormat &formatInfo =
3195         gl::GetInternalFormatInfo(getInternalFormat(index.getLevelIndex()), type);
3196     GLuint inputDepthPitch = 0;
3197     ANGLE_CHECK_GL_MATH(contextD3D, formatInfo.computeDepthPitch(
3198                                         type, area.width, area.height, unpack.alignment,
3199                                         unpack.rowLength, unpack.imageHeight, &inputDepthPitch));
3200 
3201     for (int i = 0; i < area.depth; i++)
3202     {
3203         int layer                   = area.z + i;
3204         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3205 
3206         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3207 
3208         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3209         ANGLE_TRY(TextureD3D::subImage(context, layerIndex, layerArea, format, type, unpack,
3210                                        unpackBuffer, pixels, layerOffset));
3211     }
3212 
3213     return angle::Result::Continue;
3214 }
3215 
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)3216 angle::Result TextureD3D_2DArray::setCompressedImage(const gl::Context *context,
3217                                                      const gl::ImageIndex &index,
3218                                                      GLenum internalFormat,
3219                                                      const gl::Extents &size,
3220                                                      const gl::PixelUnpackState &unpack,
3221                                                      size_t imageSize,
3222                                                      const uint8_t *pixels)
3223 {
3224     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3225 
3226     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3227 
3228     // compressed formats don't have separate sized internal formats-- we can just use the
3229     // compressed format directly
3230     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormat, size, false));
3231 
3232     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(internalFormat);
3233     GLuint inputDepthPitch               = 0;
3234     ANGLE_CHECK_GL_MATH(
3235         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1, 0, 0,
3236                                                  &inputDepthPitch));
3237 
3238     for (int i = 0; i < size.depth; i++)
3239     {
3240         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3241 
3242         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3243         ANGLE_TRY(setCompressedImageImpl(context, layerIndex, unpack, pixels, layerOffset));
3244     }
3245 
3246     return angle::Result::Continue;
3247 }
3248 
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)3249 angle::Result TextureD3D_2DArray::setCompressedSubImage(const gl::Context *context,
3250                                                         const gl::ImageIndex &index,
3251                                                         const gl::Box &area,
3252                                                         GLenum format,
3253                                                         const gl::PixelUnpackState &unpack,
3254                                                         size_t imageSize,
3255                                                         const uint8_t *pixels)
3256 {
3257     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3258 
3259     ContextD3D *contextD3D = GetImplAs<ContextD3D>(context);
3260 
3261     const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(format);
3262     GLuint inputDepthPitch               = 0;
3263     ANGLE_CHECK_GL_MATH(
3264         contextD3D, formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0,
3265                                                  &inputDepthPitch));
3266 
3267     for (int i = 0; i < area.depth; i++)
3268     {
3269         int layer                   = area.z + i;
3270         const ptrdiff_t layerOffset = (inputDepthPitch * i);
3271 
3272         gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
3273 
3274         gl::ImageIndex layerIndex = gl::ImageIndex::Make2DArray(index.getLevelIndex(), layer);
3275         ANGLE_TRY(TextureD3D::subImageCompressed(context, layerIndex, layerArea, format, unpack,
3276                                                  pixels, layerOffset));
3277         ANGLE_TRY(commitRegion(context, layerIndex, layerArea));
3278     }
3279 
3280     return angle::Result::Continue;
3281 }
3282 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3283 angle::Result TextureD3D_2DArray::copyImage(const gl::Context *context,
3284                                             const gl::ImageIndex &index,
3285                                             const gl::Rectangle &sourceArea,
3286                                             GLenum internalFormat,
3287                                             gl::Framebuffer *source)
3288 {
3289     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3290     return angle::Result::Continue;
3291 }
3292 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3293 angle::Result TextureD3D_2DArray::copySubImage(const gl::Context *context,
3294                                                const gl::ImageIndex &index,
3295                                                const gl::Offset &destOffset,
3296                                                const gl::Rectangle &sourceArea,
3297                                                gl::Framebuffer *source)
3298 {
3299     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3300 
3301     gl::Extents fbSize = source->getReadColorAttachment()->getSize();
3302     gl::Rectangle clippedSourceArea;
3303     if (!ClipRectangle(sourceArea, gl::Rectangle(0, 0, fbSize.width, fbSize.height),
3304                        &clippedSourceArea))
3305     {
3306         return angle::Result::Continue;
3307     }
3308     const gl::Offset clippedDestOffset(destOffset.x + clippedSourceArea.x - sourceArea.x,
3309                                        destOffset.y + clippedSourceArea.y - sourceArea.y,
3310                                        destOffset.z);
3311 
3312     if (!canCreateRenderTargetForImage(index))
3313     {
3314         gl::Offset destLayerOffset(clippedDestOffset.x, clippedDestOffset.y, 0);
3315         ANGLE_TRY(mImageArray[index.getLevelIndex()][clippedDestOffset.z]->copyFromFramebuffer(
3316             context, destLayerOffset, clippedSourceArea, source));
3317         mDirtyImages = true;
3318     }
3319     else
3320     {
3321         ANGLE_TRY(ensureRenderTarget(context));
3322 
3323         if (isValidLevel(index.getLevelIndex()))
3324         {
3325             ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3326             ANGLE_TRY(
3327                 mRenderer->copyImage2DArray(context, source, clippedSourceArea,
3328                                             gl::GetUnsizedFormat(getInternalFormat(getBaseLevel())),
3329                                             clippedDestOffset, mTexStorage, index.getLevelIndex()));
3330         }
3331     }
3332     return angle::Result::Continue;
3333 }
3334 
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)3335 angle::Result TextureD3D_2DArray::copyTexture(const gl::Context *context,
3336                                               const gl::ImageIndex &index,
3337                                               GLenum internalFormat,
3338                                               GLenum type,
3339                                               GLint sourceLevel,
3340                                               bool unpackFlipY,
3341                                               bool unpackPremultiplyAlpha,
3342                                               bool unpackUnmultiplyAlpha,
3343                                               const gl::Texture *source)
3344 {
3345     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3346 
3347     gl::TextureType sourceType = source->getType();
3348 
3349     const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat, type);
3350     gl::Extents size(
3351         static_cast<int>(source->getWidth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3352         static_cast<int>(source->getHeight(NonCubeTextureTypeToTarget(sourceType), sourceLevel)),
3353         static_cast<int>(source->getDepth(NonCubeTextureTypeToTarget(sourceType), sourceLevel)));
3354 
3355     ANGLE_TRY(redefineImage(context, index.getLevelIndex(), internalFormatInfo.sizedInternalFormat,
3356                             size, false));
3357 
3358     gl::Box sourceBox(0, 0, 0, size.width, size.height, size.depth);
3359     gl::Offset destOffset(0, 0, 0);
3360 
3361     gl::ImageIndex destIndex =
3362         gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth);
3363 
3364     if (!isSRGB(index.getLevelIndex()) &&
3365         canCreateRenderTargetForImage(
3366             gl::ImageIndex::Make2DArrayRange(index.getLevelIndex(), 0, size.depth)))
3367     {
3368         ANGLE_TRY(ensureRenderTarget(context));
3369         ASSERT(isValidLevel(index.getLevelIndex()));
3370         ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3371         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3372                                          sourceBox, internalFormatInfo.format,
3373                                          internalFormatInfo.type, destOffset, mTexStorage,
3374                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
3375                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3376     }
3377     else
3378     {
3379         for (int i = 0; i < size.depth; i++)
3380         {
3381             gl::ImageIndex currentSourceDepthIndex = gl::ImageIndex::Make2DArray(sourceLevel, i);
3382             gl::ImageIndex currentDestDepthIndex =
3383                 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i);
3384             ImageD3D *sourceImage = nullptr;
3385             ImageD3D *destImage   = nullptr;
3386             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3387 
3388             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestDepthIndex, &destImage));
3389             ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(context, currentSourceDepthIndex,
3390                                                             &sourceImage));
3391             gl::Box imageBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height, 1);
3392             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, imageBox, destOffset,
3393                                            unpackFlipY, unpackPremultiplyAlpha,
3394                                            unpackUnmultiplyAlpha));
3395         }
3396 
3397         mDirtyImages = true;
3398 
3399         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3400                            sourceBox.height, sourceBox.depth);
3401         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3402     }
3403 
3404     return angle::Result::Continue;
3405 }
3406 
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)3407 angle::Result TextureD3D_2DArray::copySubTexture(const gl::Context *context,
3408                                                  const gl::ImageIndex &index,
3409                                                  const gl::Offset &destOffset,
3410                                                  GLint sourceLevel,
3411                                                  const gl::Box &sourceBox,
3412                                                  bool unpackFlipY,
3413                                                  bool unpackPremultiplyAlpha,
3414                                                  bool unpackUnmultiplyAlpha,
3415                                                  const gl::Texture *source)
3416 {
3417     ASSERT(index.getTarget() == gl::TextureTarget::_2DArray);
3418 
3419     gl::ImageIndex destIndex = gl::ImageIndex::Make2DArrayRange(
3420         static_cast<GLint>(index.getLevelIndex()), destOffset.z, sourceBox.depth - destOffset.z);
3421 
3422     if (!isSRGB(destIndex.getLevelIndex()) && canCreateRenderTargetForImage(destIndex))
3423     {
3424         ANGLE_TRY(ensureRenderTarget(context));
3425         ASSERT(isValidLevel(destIndex.getLevelIndex()));
3426         ANGLE_TRY(updateStorageLevel(context, destIndex.getLevelIndex()));
3427 
3428         const gl::InternalFormat &internalFormatInfo =
3429             gl::GetSizedInternalFormatInfo(getInternalFormat(destIndex.getLevelIndex()));
3430         ANGLE_TRY(mRenderer->copyTexture(context, source, sourceLevel, gl::TextureTarget::_2DArray,
3431                                          sourceBox, internalFormatInfo.format,
3432                                          internalFormatInfo.type, destOffset, mTexStorage,
3433                                          index.getTarget(), index.getLevelIndex(), unpackFlipY,
3434                                          unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
3435     }
3436     else
3437     {
3438         for (int i = 0; i < sourceBox.depth; i++)
3439         {
3440             gl::ImageIndex currentSourceIndex =
3441                 gl::ImageIndex::Make2DArray(sourceLevel, i + sourceBox.z);
3442             gl::ImageIndex currentDestIndex =
3443                 gl::ImageIndex::Make2DArray(index.getLevelIndex(), i + destOffset.z);
3444 
3445             gl::Box currentLayerBox(sourceBox.x, sourceBox.y, 0, sourceBox.width, sourceBox.height,
3446                                     1);
3447 
3448             TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
3449             ImageD3D *sourceImage = nullptr;
3450             ANGLE_TRY(
3451                 sourceD3D->getImageAndSyncFromStorage(context, currentSourceIndex, &sourceImage));
3452 
3453             ImageD3D *destImage = nullptr;
3454             ANGLE_TRY(getImageAndSyncFromStorage(context, currentDestIndex, &destImage));
3455 
3456             ANGLE_TRY(mRenderer->copyImage(context, destImage, sourceImage, currentLayerBox,
3457                                            destOffset, unpackFlipY, unpackPremultiplyAlpha,
3458                                            unpackUnmultiplyAlpha));
3459         }
3460 
3461         mDirtyImages = true;
3462 
3463         gl::Box destRegion(destOffset.x, destOffset.y, destOffset.z, sourceBox.width,
3464                            sourceBox.height, sourceBox.depth);
3465         ANGLE_TRY(commitRegion(context, destIndex, destRegion));
3466     }
3467 
3468     return angle::Result::Continue;
3469 }
3470 
setStorage(const gl::Context * context,gl::TextureType type,size_t levels,GLenum internalFormat,const gl::Extents & size)3471 angle::Result TextureD3D_2DArray::setStorage(const gl::Context *context,
3472                                              gl::TextureType type,
3473                                              size_t levels,
3474                                              GLenum internalFormat,
3475                                              const gl::Extents &size)
3476 {
3477     ASSERT(type == gl::TextureType::_2DArray);
3478 
3479     deleteImages();
3480 
3481     for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
3482     {
3483         gl::Extents levelLayerSize(std::max(1, size.width >> level),
3484                                    std::max(1, size.height >> level), 1);
3485 
3486         mLayerCounts[level] = (level < levels ? size.depth : 0);
3487 
3488         if (mLayerCounts[level] > 0)
3489         {
3490             // Create new images for this level
3491             mImageArray[level] = new ImageD3D *[mLayerCounts[level]];
3492 
3493             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3494             {
3495                 mImageArray[level][layer] = mRenderer->createImage();
3496                 mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalFormat,
3497                                                     levelLayerSize, true);
3498             }
3499         }
3500     }
3501 
3502     // TODO(geofflang): Verify storage creation had no errors
3503     bool renderTarget = IsRenderTargetUsage(mState.getUsage());
3504     TexStoragePointer storage(context);
3505     storage.reset(mRenderer->createTextureStorage2DArray(
3506         internalFormat, renderTarget, size.width, size.height, size.depth, static_cast<int>(levels),
3507         mState.getLabel()));
3508 
3509     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3510     storage.release();
3511 
3512     ANGLE_TRY(updateStorage(context));
3513 
3514     mImmutable = true;
3515 
3516     return angle::Result::Continue;
3517 }
3518 
bindTexImage(const gl::Context * context,egl::Surface * surface)3519 angle::Result TextureD3D_2DArray::bindTexImage(const gl::Context *context, egl::Surface *surface)
3520 {
3521     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3522     return angle::Result::Continue;
3523 }
3524 
releaseTexImage(const gl::Context * context)3525 angle::Result TextureD3D_2DArray::releaseTexImage(const gl::Context *context)
3526 {
3527     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3528     return angle::Result::Continue;
3529 }
3530 
initMipmapImages(const gl::Context * context)3531 angle::Result TextureD3D_2DArray::initMipmapImages(const gl::Context *context)
3532 {
3533     const GLuint baseLevel = mState.getEffectiveBaseLevel();
3534     const GLuint maxLevel  = mState.getMipmapMaxLevel();
3535     int baseWidth          = getLevelZeroWidth();
3536     int baseHeight         = getLevelZeroHeight();
3537     int baseDepth          = getLayerCount(getBaseLevel());
3538     GLenum baseFormat      = getBaseLevelInternalFormat();
3539 
3540     // Purge array levels baseLevel + 1 through q and reset them to represent the generated mipmap
3541     // levels.
3542     for (GLuint level = baseLevel + 1u; level <= maxLevel; level++)
3543     {
3544         ASSERT((baseWidth >> level) > 0 || (baseHeight >> level) > 0);
3545         gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
3546                                    std::max(baseHeight >> level, 1), baseDepth);
3547         ANGLE_TRY(redefineImage(context, level, baseFormat, levelLayerSize, false));
3548     }
3549 
3550     return angle::Result::Continue;
3551 }
3552 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)3553 angle::Result TextureD3D_2DArray::getRenderTarget(const gl::Context *context,
3554                                                   const gl::ImageIndex &index,
3555                                                   GLsizei samples,
3556                                                   RenderTargetD3D **outRT)
3557 {
3558     // ensure the underlying texture is created
3559     ANGLE_TRY(ensureRenderTarget(context));
3560     ANGLE_TRY(updateStorageLevel(context, index.getLevelIndex()));
3561     return mTexStorage->getRenderTarget(context, index, samples, outRT);
3562 }
3563 
initializeStorage(const gl::Context * context,bool renderTarget)3564 angle::Result TextureD3D_2DArray::initializeStorage(const gl::Context *context, bool renderTarget)
3565 {
3566     // Only initialize the first time this texture is used as a render target or shader resource
3567     if (mTexStorage)
3568     {
3569         return angle::Result::Continue;
3570     }
3571 
3572     // do not attempt to create storage for nonexistant data
3573     if (!isLevelComplete(getBaseLevel()))
3574     {
3575         return angle::Result::Continue;
3576     }
3577 
3578     bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mState.getUsage()));
3579 
3580     TexStoragePointer storage(context);
3581     ANGLE_TRY(createCompleteStorage(createRenderTarget, &storage));
3582 
3583     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
3584     storage.release();
3585 
3586     ASSERT(mTexStorage);
3587 
3588     // flush image data to the storage
3589     ANGLE_TRY(updateStorage(context));
3590 
3591     return angle::Result::Continue;
3592 }
3593 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const3594 angle::Result TextureD3D_2DArray::createCompleteStorage(bool renderTarget,
3595                                                         TexStoragePointer *outStorage) const
3596 {
3597     GLsizei width         = getLevelZeroWidth();
3598     GLsizei height        = getLevelZeroHeight();
3599     GLsizei depth         = getLayerCount(getBaseLevel());
3600     GLenum internalFormat = getBaseLevelInternalFormat();
3601 
3602     ASSERT(width > 0 && height > 0 && depth > 0);
3603 
3604     // use existing storage level count, when previously specified by TexStorage*D
3605     GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
3606 
3607     // TODO(geofflang): Verify storage creation succeeds
3608     outStorage->reset(mRenderer->createTextureStorage2DArray(
3609         internalFormat, renderTarget, width, height, depth, levels, mState.getLabel()));
3610 
3611     return angle::Result::Continue;
3612 }
3613 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)3614 angle::Result TextureD3D_2DArray::setCompleteTexStorage(const gl::Context *context,
3615                                                         TextureStorage *newCompleteTexStorage)
3616 {
3617     ANGLE_TRY(releaseTexStorage(context));
3618     mTexStorage = newCompleteTexStorage;
3619     mTexStorageObserverBinding.bind(mTexStorage);
3620     mDirtyImages = true;
3621 
3622     // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
3623     ASSERT(!mTexStorage->isManaged());
3624 
3625     return angle::Result::Continue;
3626 }
3627 
updateStorage(const gl::Context * context)3628 angle::Result TextureD3D_2DArray::updateStorage(const gl::Context *context)
3629 {
3630     if (!mDirtyImages)
3631     {
3632         return angle::Result::Continue;
3633     }
3634 
3635     ASSERT(mTexStorage != nullptr);
3636     GLint storageLevels = mTexStorage->getLevelCount();
3637     for (int level = 0; level < storageLevels; level++)
3638     {
3639         if (isLevelComplete(level))
3640         {
3641             ANGLE_TRY(updateStorageLevel(context, level));
3642         }
3643     }
3644 
3645     mDirtyImages = false;
3646     return angle::Result::Continue;
3647 }
3648 
isValidLevel(int level) const3649 bool TextureD3D_2DArray::isValidLevel(int level) const
3650 {
3651     return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
3652 }
3653 
isLevelComplete(int level) const3654 bool TextureD3D_2DArray::isLevelComplete(int level) const
3655 {
3656     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
3657 
3658     if (isImmutable())
3659     {
3660         return true;
3661     }
3662 
3663     GLsizei width  = getLevelZeroWidth();
3664     GLsizei height = getLevelZeroHeight();
3665 
3666     if (width <= 0 || height <= 0)
3667     {
3668         return false;
3669     }
3670 
3671     // Layers check needs to happen after the above checks, otherwise out-of-range base level may be
3672     // queried.
3673     GLsizei layers = getLayerCount(getBaseLevel());
3674 
3675     if (layers <= 0)
3676     {
3677         return false;
3678     }
3679 
3680     if (level == static_cast<int>(getBaseLevel()))
3681     {
3682         return true;
3683     }
3684 
3685     if (getInternalFormat(level) != getInternalFormat(getBaseLevel()))
3686     {
3687         return false;
3688     }
3689 
3690     if (getWidth(level) != std::max(1, width >> level))
3691     {
3692         return false;
3693     }
3694 
3695     if (getHeight(level) != std::max(1, height >> level))
3696     {
3697         return false;
3698     }
3699 
3700     if (getLayerCount(level) != layers)
3701     {
3702         return false;
3703     }
3704 
3705     return true;
3706 }
3707 
isImageComplete(const gl::ImageIndex & index) const3708 bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
3709 {
3710     return isLevelComplete(index.getLevelIndex());
3711 }
3712 
updateStorageLevel(const gl::Context * context,int level)3713 angle::Result TextureD3D_2DArray::updateStorageLevel(const gl::Context *context, int level)
3714 {
3715     ASSERT(level >= 0 && level < static_cast<int>(ArraySize(mLayerCounts)));
3716     ASSERT(isLevelComplete(level));
3717 
3718     for (int layer = 0; layer < mLayerCounts[level]; layer++)
3719     {
3720         ASSERT(mImageArray[level] != nullptr && mImageArray[level][layer] != nullptr);
3721         if (mImageArray[level][layer]->isDirty())
3722         {
3723             gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
3724             gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
3725             ANGLE_TRY(commitRegion(context, index, region));
3726         }
3727     }
3728 
3729     return angle::Result::Continue;
3730 }
3731 
deleteImages()3732 void TextureD3D_2DArray::deleteImages()
3733 {
3734     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
3735     {
3736         for (int layer = 0; layer < mLayerCounts[level]; ++layer)
3737         {
3738             delete mImageArray[level][layer];
3739         }
3740         delete[] mImageArray[level];
3741         mImageArray[level]  = nullptr;
3742         mLayerCounts[level] = 0;
3743     }
3744 }
3745 
redefineImage(const gl::Context * context,GLint level,GLenum internalformat,const gl::Extents & size,bool forceRelease)3746 angle::Result TextureD3D_2DArray::redefineImage(const gl::Context *context,
3747                                                 GLint level,
3748                                                 GLenum internalformat,
3749                                                 const gl::Extents &size,
3750                                                 bool forceRelease)
3751 {
3752     // If there currently is a corresponding storage texture image, it has these parameters
3753     const int storageWidth     = std::max(1, getLevelZeroWidth() >> level);
3754     const int storageHeight    = std::max(1, getLevelZeroHeight() >> level);
3755     const GLuint baseLevel     = getBaseLevel();
3756     const GLenum storageFormat = getBaseLevelInternalFormat();
3757 
3758     int storageDepth = 0;
3759     if (baseLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
3760     {
3761         storageDepth = getLayerCount(baseLevel);
3762     }
3763 
3764     // Only reallocate the layers if the size doesn't match
3765     if (size.depth != mLayerCounts[level])
3766     {
3767         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3768         {
3769             SafeDelete(mImageArray[level][layer]);
3770         }
3771         SafeDeleteArray(mImageArray[level]);
3772         mLayerCounts[level] = size.depth;
3773 
3774         if (size.depth > 0)
3775         {
3776             mImageArray[level] = new ImageD3D *[size.depth];
3777             for (int layer = 0; layer < mLayerCounts[level]; layer++)
3778             {
3779                 mImageArray[level][layer] = mRenderer->createImage();
3780             }
3781         }
3782     }
3783 
3784     if (size.depth > 0)
3785     {
3786         for (int layer = 0; layer < mLayerCounts[level]; layer++)
3787         {
3788             mImageArray[level][layer]->redefine(gl::TextureType::_2DArray, internalformat,
3789                                                 gl::Extents(size.width, size.height, 1),
3790                                                 forceRelease);
3791             mDirtyImages = mDirtyImages || mImageArray[level][layer]->isDirty();
3792         }
3793     }
3794 
3795     if (mTexStorage)
3796     {
3797         const int storageLevels = mTexStorage->getLevelCount();
3798 
3799         if ((level >= storageLevels && storageLevels != 0) || size.width != storageWidth ||
3800             size.height != storageHeight || size.depth != storageDepth ||
3801             internalformat != storageFormat)  // Discard mismatched storage
3802         {
3803             markAllImagesDirty();
3804             ANGLE_TRY(releaseTexStorage(context));
3805         }
3806     }
3807 
3808     return angle::Result::Continue;
3809 }
3810 
imageIterator() const3811 gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
3812 {
3813     return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
3814 }
3815 
getImageIndex(GLint mip,GLint layer) const3816 gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
3817 {
3818     return gl::ImageIndex::Make2DArray(mip, layer);
3819 }
3820 
isValidIndex(const gl::ImageIndex & index) const3821 bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
3822 {
3823     // Check for having a storage and the right type of index
3824     if (!mTexStorage || index.getType() != gl::TextureType::_2DArray)
3825     {
3826         return false;
3827     }
3828 
3829     // Check the mip index
3830     if (index.getLevelIndex() < 0 || index.getLevelIndex() >= mTexStorage->getLevelCount())
3831     {
3832         return false;
3833     }
3834 
3835     // Check the layer index
3836     return (!index.hasLayer() || (index.getLayerIndex() >= 0 &&
3837                                   index.getLayerIndex() < mLayerCounts[index.getLevelIndex()]));
3838 }
3839 
markAllImagesDirty()3840 void TextureD3D_2DArray::markAllImagesDirty()
3841 {
3842     for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
3843     {
3844         for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
3845         {
3846             mImageArray[dirtyLevel][dirtyLayer]->markDirty();
3847         }
3848     }
3849     mDirtyImages = true;
3850 }
3851 
TextureD3DImmutableBase(const gl::TextureState & state,RendererD3D * renderer)3852 TextureD3DImmutableBase::TextureD3DImmutableBase(const gl::TextureState &state,
3853                                                  RendererD3D *renderer)
3854     : TextureD3D(state, renderer)
3855 {}
3856 
~TextureD3DImmutableBase()3857 TextureD3DImmutableBase::~TextureD3DImmutableBase() {}
3858 
getImage(const gl::ImageIndex & index) const3859 ImageD3D *TextureD3DImmutableBase::getImage(const gl::ImageIndex &index) const
3860 {
3861     return nullptr;
3862 }
3863 
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)3864 angle::Result TextureD3DImmutableBase::setImage(const gl::Context *context,
3865                                                 const gl::ImageIndex &index,
3866                                                 GLenum internalFormat,
3867                                                 const gl::Extents &size,
3868                                                 GLenum format,
3869                                                 GLenum type,
3870                                                 const gl::PixelUnpackState &unpack,
3871                                                 gl::Buffer *unpackBuffer,
3872                                                 const uint8_t *pixels)
3873 {
3874     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3875     return angle::Result::Continue;
3876 }
3877 
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)3878 angle::Result TextureD3DImmutableBase::setSubImage(const gl::Context *context,
3879                                                    const gl::ImageIndex &index,
3880                                                    const gl::Box &area,
3881                                                    GLenum format,
3882                                                    GLenum type,
3883                                                    const gl::PixelUnpackState &unpack,
3884                                                    gl::Buffer *unpackBuffer,
3885                                                    const uint8_t *pixels)
3886 {
3887     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3888     return angle::Result::Continue;
3889 }
3890 
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)3891 angle::Result TextureD3DImmutableBase::setCompressedImage(const gl::Context *context,
3892                                                           const gl::ImageIndex &index,
3893                                                           GLenum internalFormat,
3894                                                           const gl::Extents &size,
3895                                                           const gl::PixelUnpackState &unpack,
3896                                                           size_t imageSize,
3897                                                           const uint8_t *pixels)
3898 {
3899     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3900     return angle::Result::Continue;
3901 }
3902 
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)3903 angle::Result TextureD3DImmutableBase::setCompressedSubImage(const gl::Context *context,
3904                                                              const gl::ImageIndex &index,
3905                                                              const gl::Box &area,
3906                                                              GLenum format,
3907                                                              const gl::PixelUnpackState &unpack,
3908                                                              size_t imageSize,
3909                                                              const uint8_t *pixels)
3910 {
3911     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3912     return angle::Result::Continue;
3913 }
3914 
copyImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Rectangle & sourceArea,GLenum internalFormat,gl::Framebuffer * source)3915 angle::Result TextureD3DImmutableBase::copyImage(const gl::Context *context,
3916                                                  const gl::ImageIndex &index,
3917                                                  const gl::Rectangle &sourceArea,
3918                                                  GLenum internalFormat,
3919                                                  gl::Framebuffer *source)
3920 {
3921     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3922     return angle::Result::Continue;
3923 }
3924 
copySubImage(const gl::Context * context,const gl::ImageIndex & index,const gl::Offset & destOffset,const gl::Rectangle & sourceArea,gl::Framebuffer * source)3925 angle::Result TextureD3DImmutableBase::copySubImage(const gl::Context *context,
3926                                                     const gl::ImageIndex &index,
3927                                                     const gl::Offset &destOffset,
3928                                                     const gl::Rectangle &sourceArea,
3929                                                     gl::Framebuffer *source)
3930 {
3931     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3932     return angle::Result::Continue;
3933 }
3934 
bindTexImage(const gl::Context * context,egl::Surface * surface)3935 angle::Result TextureD3DImmutableBase::bindTexImage(const gl::Context *context,
3936                                                     egl::Surface *surface)
3937 {
3938     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3939     return angle::Result::Continue;
3940 }
3941 
releaseTexImage(const gl::Context * context)3942 angle::Result TextureD3DImmutableBase::releaseTexImage(const gl::Context *context)
3943 {
3944     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3945     return angle::Result::Continue;
3946 }
3947 
TextureD3D_External(const gl::TextureState & state,RendererD3D * renderer)3948 TextureD3D_External::TextureD3D_External(const gl::TextureState &state, RendererD3D *renderer)
3949     : TextureD3DImmutableBase(state, renderer)
3950 {}
3951 
~TextureD3D_External()3952 TextureD3D_External::~TextureD3D_External() {}
3953 
getLayerCount(int level) const3954 GLsizei TextureD3D_External::getLayerCount(int level) const
3955 {
3956     return 1;
3957 }
3958 
setImageExternal(const gl::Context * context,gl::TextureType type,egl::Stream * stream,const egl::Stream::GLTextureDescription & desc)3959 angle::Result TextureD3D_External::setImageExternal(const gl::Context *context,
3960                                                     gl::TextureType type,
3961                                                     egl::Stream *stream,
3962                                                     const egl::Stream::GLTextureDescription &desc)
3963 {
3964     ASSERT(type == gl::TextureType::External);
3965 
3966     ANGLE_TRY(releaseTexStorage(context));
3967 
3968     // If the stream is null, the external image is unbound and we release the storage
3969     if (stream != nullptr)
3970     {
3971         mTexStorage = mRenderer->createTextureStorageExternal(stream, desc, mState.getLabel());
3972     }
3973 
3974     return angle::Result::Continue;
3975 }
3976 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)3977 angle::Result TextureD3D_External::setEGLImageTarget(const gl::Context *context,
3978                                                      gl::TextureType type,
3979                                                      egl::Image *image)
3980 {
3981     EGLImageD3D *eglImaged3d = GetImplAs<EGLImageD3D>(image);
3982 
3983     // Pass in the RenderTargetD3D here: createTextureStorage can't generate an error.
3984     RenderTargetD3D *renderTargetD3D = nullptr;
3985     ANGLE_TRY(eglImaged3d->getRenderTarget(context, &renderTargetD3D));
3986 
3987     ANGLE_TRY(releaseTexStorage(context));
3988     mTexStorage =
3989         mRenderer->createTextureStorageEGLImage(eglImaged3d, renderTargetD3D, mState.getLabel());
3990 
3991     return angle::Result::Continue;
3992 }
3993 
initMipmapImages(const gl::Context * context)3994 angle::Result TextureD3D_External::initMipmapImages(const gl::Context *context)
3995 {
3996     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
3997     return angle::Result::Stop;
3998 }
3999 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4000 angle::Result TextureD3D_External::getRenderTarget(const gl::Context *context,
4001                                                    const gl::ImageIndex &index,
4002                                                    GLsizei samples,
4003                                                    RenderTargetD3D **outRT)
4004 {
4005     UNREACHABLE();
4006     return angle::Result::Stop;
4007 }
4008 
isImageComplete(const gl::ImageIndex & index) const4009 bool TextureD3D_External::isImageComplete(const gl::ImageIndex &index) const
4010 {
4011     return (index.getLevelIndex() == 0) ? (mTexStorage != nullptr) : false;
4012 }
4013 
initializeStorage(const gl::Context * context,bool renderTarget)4014 angle::Result TextureD3D_External::initializeStorage(const gl::Context *context, bool renderTarget)
4015 {
4016     // Texture storage is created when an external image is bound
4017     ASSERT(mTexStorage);
4018     return angle::Result::Continue;
4019 }
4020 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4021 angle::Result TextureD3D_External::createCompleteStorage(bool renderTarget,
4022                                                          TexStoragePointer *outStorage) const
4023 {
4024     UNREACHABLE();
4025     return angle::Result::Continue;
4026 }
4027 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4028 angle::Result TextureD3D_External::setCompleteTexStorage(const gl::Context *context,
4029                                                          TextureStorage *newCompleteTexStorage)
4030 {
4031     UNREACHABLE();
4032     return angle::Result::Continue;
4033 }
4034 
updateStorage(const gl::Context * context)4035 angle::Result TextureD3D_External::updateStorage(const gl::Context *context)
4036 {
4037     // Texture storage does not need to be updated since it is already loaded with the latest
4038     // external image
4039     ASSERT(mTexStorage);
4040     return angle::Result::Continue;
4041 }
4042 
imageIterator() const4043 gl::ImageIndexIterator TextureD3D_External::imageIterator() const
4044 {
4045     return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
4046 }
4047 
getImageIndex(GLint mip,GLint) const4048 gl::ImageIndex TextureD3D_External::getImageIndex(GLint mip, GLint /*layer*/) const
4049 {
4050     // "layer" does not apply to 2D Textures.
4051     return gl::ImageIndex::Make2D(mip);
4052 }
4053 
isValidIndex(const gl::ImageIndex & index) const4054 bool TextureD3D_External::isValidIndex(const gl::ImageIndex &index) const
4055 {
4056     return (mTexStorage && index.getType() == gl::TextureType::External &&
4057             index.getLevelIndex() == 0);
4058 }
4059 
markAllImagesDirty()4060 void TextureD3D_External::markAllImagesDirty()
4061 {
4062     UNREACHABLE();
4063 }
4064 
TextureD3D_2DMultisample(const gl::TextureState & state,RendererD3D * renderer)4065 TextureD3D_2DMultisample::TextureD3D_2DMultisample(const gl::TextureState &state,
4066                                                    RendererD3D *renderer)
4067     : TextureD3DImmutableBase(state, renderer)
4068 {}
4069 
~TextureD3D_2DMultisample()4070 TextureD3D_2DMultisample::~TextureD3D_2DMultisample() {}
4071 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4072 angle::Result TextureD3D_2DMultisample::setStorageMultisample(const gl::Context *context,
4073                                                               gl::TextureType type,
4074                                                               GLsizei samples,
4075                                                               GLint internalformat,
4076                                                               const gl::Extents &size,
4077                                                               bool fixedSampleLocations)
4078 {
4079     ASSERT(type == gl::TextureType::_2DMultisample && size.depth == 1);
4080 
4081     // We allocate storage immediately instead of doing it lazily like other TextureD3D classes do.
4082     // This requires less state in this class.
4083     TexStoragePointer storage(context);
4084     storage.reset(mRenderer->createTextureStorage2DMultisample(
4085         internalformat, size.width, size.height, static_cast<int>(0), samples, fixedSampleLocations,
4086         mState.getLabel()));
4087 
4088     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4089     storage.release();
4090 
4091     mImmutable = true;
4092 
4093     return angle::Result::Continue;
4094 }
4095 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4096 angle::Result TextureD3D_2DMultisample::setEGLImageTarget(const gl::Context *context,
4097                                                           gl::TextureType type,
4098                                                           egl::Image *image)
4099 {
4100     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4101     return angle::Result::Continue;
4102 }
4103 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4104 angle::Result TextureD3D_2DMultisample::getRenderTarget(const gl::Context *context,
4105                                                         const gl::ImageIndex &index,
4106                                                         GLsizei samples,
4107                                                         RenderTargetD3D **outRT)
4108 {
4109     ASSERT(!index.hasLayer());
4110 
4111     // ensure the underlying texture is created
4112     ANGLE_TRY(ensureRenderTarget(context));
4113 
4114     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4115 }
4116 
imageIterator() const4117 gl::ImageIndexIterator TextureD3D_2DMultisample::imageIterator() const
4118 {
4119     return gl::ImageIndexIterator::Make2DMultisample();
4120 }
4121 
getImageIndex(GLint mip,GLint layer) const4122 gl::ImageIndex TextureD3D_2DMultisample::getImageIndex(GLint mip, GLint layer) const
4123 {
4124     return gl::ImageIndex::Make2DMultisample();
4125 }
4126 
isValidIndex(const gl::ImageIndex & index) const4127 bool TextureD3D_2DMultisample::isValidIndex(const gl::ImageIndex &index) const
4128 {
4129     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisample &&
4130             index.getLevelIndex() == 0);
4131 }
4132 
getLayerCount(int level) const4133 GLsizei TextureD3D_2DMultisample::getLayerCount(int level) const
4134 {
4135     return 1;
4136 }
4137 
markAllImagesDirty()4138 void TextureD3D_2DMultisample::markAllImagesDirty() {}
4139 
initializeStorage(const gl::Context * context,bool renderTarget)4140 angle::Result TextureD3D_2DMultisample::initializeStorage(const gl::Context *context,
4141                                                           bool renderTarget)
4142 {
4143     // initializeStorage should only be called in a situation where the texture already has storage
4144     // associated with it (storage is created in setStorageMultisample).
4145     ASSERT(mTexStorage);
4146     return angle::Result::Continue;
4147 }
4148 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4149 angle::Result TextureD3D_2DMultisample::createCompleteStorage(bool renderTarget,
4150                                                               TexStoragePointer *outStorage) const
4151 {
4152     UNREACHABLE();
4153     outStorage->reset(mTexStorage);
4154     return angle::Result::Continue;
4155 }
4156 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4157 angle::Result TextureD3D_2DMultisample::setCompleteTexStorage(const gl::Context *context,
4158                                                               TextureStorage *newCompleteTexStorage)
4159 {
4160     // These textures are immutable, so this should only be ever called once.
4161     ASSERT(!mTexStorage);
4162     mTexStorage = newCompleteTexStorage;
4163     mTexStorageObserverBinding.bind(mTexStorage);
4164     return angle::Result::Continue;
4165 }
4166 
updateStorage(const gl::Context * context)4167 angle::Result TextureD3D_2DMultisample::updateStorage(const gl::Context *context)
4168 {
4169     return angle::Result::Continue;
4170 }
4171 
initMipmapImages(const gl::Context * context)4172 angle::Result TextureD3D_2DMultisample::initMipmapImages(const gl::Context *context)
4173 {
4174     UNREACHABLE();
4175     return angle::Result::Continue;
4176 }
4177 
isImageComplete(const gl::ImageIndex & index) const4178 bool TextureD3D_2DMultisample::isImageComplete(const gl::ImageIndex &index) const
4179 {
4180     return true;
4181 }
4182 
TextureD3D_2DMultisampleArray(const gl::TextureState & state,RendererD3D * renderer)4183 TextureD3D_2DMultisampleArray::TextureD3D_2DMultisampleArray(const gl::TextureState &state,
4184                                                              RendererD3D *renderer)
4185     : TextureD3DImmutableBase(state, renderer)
4186 {}
4187 
~TextureD3D_2DMultisampleArray()4188 TextureD3D_2DMultisampleArray::~TextureD3D_2DMultisampleArray() {}
4189 
setStorageMultisample(const gl::Context * context,gl::TextureType type,GLsizei samples,GLint internalformat,const gl::Extents & size,bool fixedSampleLocations)4190 angle::Result TextureD3D_2DMultisampleArray::setStorageMultisample(const gl::Context *context,
4191                                                                    gl::TextureType type,
4192                                                                    GLsizei samples,
4193                                                                    GLint internalformat,
4194                                                                    const gl::Extents &size,
4195                                                                    bool fixedSampleLocations)
4196 {
4197     ASSERT(type == gl::TextureType::_2DMultisampleArray);
4198 
4199     mLayerCount = size.depth;
4200 
4201     TexStoragePointer storage(context);
4202     storage.reset(mRenderer->createTextureStorage2DMultisampleArray(
4203         internalformat, size.width, size.height, size.depth, static_cast<int>(0), samples,
4204         fixedSampleLocations, mState.getLabel()));
4205 
4206     ANGLE_TRY(setCompleteTexStorage(context, storage.get()));
4207     storage.release();
4208 
4209     mImmutable = true;
4210 
4211     return angle::Result::Continue;
4212 }
4213 
setEGLImageTarget(const gl::Context * context,gl::TextureType type,egl::Image * image)4214 angle::Result TextureD3D_2DMultisampleArray::setEGLImageTarget(const gl::Context *context,
4215                                                                gl::TextureType type,
4216                                                                egl::Image *image)
4217 {
4218     ANGLE_HR_UNREACHABLE(GetImplAs<ContextD3D>(context));
4219     return angle::Result::Continue;
4220 }
4221 
getRenderTarget(const gl::Context * context,const gl::ImageIndex & index,GLsizei samples,RenderTargetD3D ** outRT)4222 angle::Result TextureD3D_2DMultisampleArray::getRenderTarget(const gl::Context *context,
4223                                                              const gl::ImageIndex &index,
4224                                                              GLsizei samples,
4225                                                              RenderTargetD3D **outRT)
4226 {
4227     // ensure the underlying texture is created
4228     ANGLE_TRY(ensureRenderTarget(context));
4229 
4230     return mTexStorage->getRenderTarget(context, index, samples, outRT);
4231 }
4232 
imageIterator() const4233 gl::ImageIndexIterator TextureD3D_2DMultisampleArray::imageIterator() const
4234 {
4235     return gl::ImageIndexIterator::Make2DMultisampleArray(&mLayerCount);
4236 }
4237 
getImageIndex(GLint mip,GLint layer) const4238 gl::ImageIndex TextureD3D_2DMultisampleArray::getImageIndex(GLint mip, GLint layer) const
4239 {
4240     return gl::ImageIndex::Make2DMultisampleArray(layer);
4241 }
4242 
isValidIndex(const gl::ImageIndex & index) const4243 bool TextureD3D_2DMultisampleArray::isValidIndex(const gl::ImageIndex &index) const
4244 {
4245     return (mTexStorage && index.getType() == gl::TextureType::_2DMultisampleArray &&
4246             index.getLevelIndex() == 0);
4247 }
4248 
getLayerCount(int level) const4249 GLsizei TextureD3D_2DMultisampleArray::getLayerCount(int level) const
4250 {
4251     return mLayerCount;
4252 }
4253 
markAllImagesDirty()4254 void TextureD3D_2DMultisampleArray::markAllImagesDirty() {}
4255 
initializeStorage(const gl::Context * context,bool renderTarget)4256 angle::Result TextureD3D_2DMultisampleArray::initializeStorage(const gl::Context *context,
4257                                                                bool renderTarget)
4258 {
4259     // initializeStorage should only be called in a situation where the texture already has storage
4260     // associated with it (storage is created in setStorageMultisample).
4261     ASSERT(mTexStorage);
4262     return angle::Result::Continue;
4263 }
4264 
createCompleteStorage(bool renderTarget,TexStoragePointer * outStorage) const4265 angle::Result TextureD3D_2DMultisampleArray::createCompleteStorage(
4266     bool renderTarget,
4267     TexStoragePointer *outStorage) const
4268 {
4269     UNREACHABLE();
4270     outStorage->reset(mTexStorage);
4271     return angle::Result::Continue;
4272 }
4273 
setCompleteTexStorage(const gl::Context * context,TextureStorage * newCompleteTexStorage)4274 angle::Result TextureD3D_2DMultisampleArray::setCompleteTexStorage(
4275     const gl::Context *context,
4276     TextureStorage *newCompleteTexStorage)
4277 {
4278     // These textures are immutable, so this should only be ever called once.
4279     ASSERT(!mTexStorage);
4280     mTexStorage = newCompleteTexStorage;
4281     mTexStorageObserverBinding.bind(mTexStorage);
4282     return angle::Result::Continue;
4283 }
4284 
updateStorage(const gl::Context * context)4285 angle::Result TextureD3D_2DMultisampleArray::updateStorage(const gl::Context *context)
4286 {
4287     return angle::Result::Continue;
4288 }
4289 
initMipmapImages(const gl::Context * context)4290 angle::Result TextureD3D_2DMultisampleArray::initMipmapImages(const gl::Context *context)
4291 {
4292     UNIMPLEMENTED();
4293     return angle::Result::Continue;
4294 }
4295 
isImageComplete(const gl::ImageIndex & index) const4296 bool TextureD3D_2DMultisampleArray::isImageComplete(const gl::ImageIndex &index) const
4297 {
4298     return true;
4299 }
4300 
4301 }  // namespace rx
4302