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