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