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