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