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