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