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