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