blob: 7b7c822dca6cf2957e94669910df0681fee49906 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
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
Jamie Madillfb0580a2014-11-27 14:03:52 -05009#include "libANGLE/renderer/d3d/TextureD3D.h"
10
11#include "common/mathutil.h"
12#include "common/utilities.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Buffer.h"
14#include "libANGLE/Framebuffer.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050015#include "libANGLE/Surface.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Texture.h"
17#include "libANGLE/formatutils.h"
18#include "libANGLE/renderer/BufferImpl.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/renderer/d3d/BufferD3D.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/renderer/d3d/ImageD3D.h"
21#include "libANGLE/renderer/d3d/RendererD3D.h"
Geoff Langc2e75af2015-01-05 14:26:24 -050022#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050023#include "libANGLE/renderer/d3d/SurfaceD3D.h"
24#include "libANGLE/renderer/d3d/TextureStorage.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
Geoff Lang0a4f1e22014-12-17 12:33:26 -050032gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const uint8_t **pointerOut)
Jamie Madillc751d1e2014-10-21 17:46:29 -040033{
34 if (unpack.pixelBuffer.id() != 0)
35 {
36 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
37 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
38 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
39
40 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
41 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
Jamie Madill9ae396b2014-10-21 17:46:30 -040042 BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation());
43 ASSERT(bufferD3D);
Jamie Madillc751d1e2014-10-21 17:46:29 -040044 const uint8_t *bufferData = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -040045 gl::Error error = bufferD3D->getData(&bufferData);
Jamie Madillc751d1e2014-10-21 17:46:29 -040046 if (error.isError())
47 {
48 return error;
49 }
50
51 *pointerOut = bufferData + offset;
52 }
53 else
54 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -050055 *pointerOut = pixels;
Jamie Madillc751d1e2014-10-21 17:46:29 -040056 }
57
58 return gl::Error(GL_NO_ERROR);
59}
60
Brandon Jonesf47bebc2014-07-09 14:28:42 -070061bool IsRenderTargetUsage(GLenum usage)
62{
63 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
64}
65
Jamie Madillc751d1e2014-10-21 17:46:29 -040066}
67
Jamie Madill93e13fb2014-11-06 15:27:25 -050068TextureD3D::TextureD3D(RendererD3D *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 : mRenderer(renderer),
70 mUsage(GL_NONE),
71 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040072 mImmutable(false),
73 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070074{
75}
76
77TextureD3D::~TextureD3D()
78{
79}
80
Brandon Jones6053a522014-07-25 16:22:09 -070081TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
82{
83 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
84 return static_cast<TextureD3D*>(texture);
85}
86
Jamie Madill2f06dbf2014-09-18 15:08:50 -040087TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070088{
89 // ensure the underlying texture is created
90 initializeStorage(false);
91
Jamie Madill98553e32014-09-30 16:33:50 -040092 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070093 {
94 updateStorage();
95 }
96
Jamie Madill98553e32014-09-30 16:33:50 -040097 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070098}
99
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700100GLint TextureD3D::getBaseLevelWidth() const
101{
Geoff Langb4dedf32015-01-05 14:08:53 -0500102 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700103 return (baseImage ? baseImage->getWidth() : 0);
104}
105
106GLint TextureD3D::getBaseLevelHeight() const
107{
Geoff Langb4dedf32015-01-05 14:08:53 -0500108 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700109 return (baseImage ? baseImage->getHeight() : 0);
110}
111
112GLint TextureD3D::getBaseLevelDepth() const
113{
Geoff Langb4dedf32015-01-05 14:08:53 -0500114 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700115 return (baseImage ? baseImage->getDepth() : 0);
116}
117
118// Note: "base level image" is loosely defined to be any image from the base level,
119// where in the base of 2D array textures and cube maps there are several. Don't use
120// the base level image for anything except querying texture format and size.
121GLenum TextureD3D::getBaseLevelInternalFormat() const
122{
Geoff Langb4dedf32015-01-05 14:08:53 -0500123 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
125}
126
Geoff Langb4dedf32015-01-05 14:08:53 -0500127bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
Jamie Madillec6de4e2014-10-20 10:59:56 -0400128{
129 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
130 {
131 return false;
132 }
133
134 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
135
136 // We can only handle full updates for depth-stencil textures, so to avoid complications
137 // disable them entirely.
138 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
139 {
140 return false;
141 }
142
143 // TODO(jmadill): Handle compressed internal formats
144 return (mTexStorage && !internalFormat.compressed);
145}
146
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500147gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
Geoff Langb4dedf32015-01-05 14:08:53 -0500149 ImageD3D *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400150 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400151
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152 // No-op
153 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
154 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400155 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700156 }
157
158 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
159 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill9aca0592014-10-06 16:26:59 -0400160 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400161 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
162 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400164 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 }
166
167 if (pixelData != NULL)
168 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400169 gl::Error error(GL_NO_ERROR);
170
Jamie Madillec6de4e2014-10-20 10:59:56 -0400171 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400172 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400173 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400174 }
175 else
176 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500177 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
178 error = image->loadData(fullImageArea, unpack.alignment, type, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400179 }
180
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400181 if (error.isError())
182 {
183 return error;
184 }
185
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700186 mDirtyImages = true;
187 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400188
189 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700190}
191
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500192gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type,
193 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400196 const uint8_t *pixelData = NULL;
197 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
198 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700199 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400200 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700201 }
202
203 if (pixelData != NULL)
204 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500205 ImageD3D *image = getImage(index);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400206 ASSERT(image);
207
Jamie Madillec6de4e2014-10-20 10:59:56 -0400208 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500210 return mTexStorage->setData(index, image, &area, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400211 }
212
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500213 gl::Error error = image->loadData(area, unpack.alignment, type, pixelData);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400214 if (error.isError())
215 {
216 return error;
217 }
218
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500219 error = commitRegion(index, area);
Jamie Madille6b6da02014-10-02 11:03:14 -0400220 if (error.isError())
221 {
222 return error;
223 }
224
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700225 mDirtyImages = true;
226 }
227
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400228 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700229}
230
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500231gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700232{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400233 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
234 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
235 const uint8_t *pixelData = NULL;
236 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
237 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400239 return error;
240 }
241
242 if (pixelData != NULL)
243 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500244 ImageD3D *image = getImage(index);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500245 ASSERT(image);
246
247 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
248 gl::Error error = image->loadCompressedData(fullImageArea, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400249 if (error.isError())
250 {
251 return error;
252 }
253
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700254 mDirtyImages = true;
255 }
Geoff Langb5348332014-09-02 13:16:34 -0400256
257 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258}
259
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500260gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format,
261 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700262{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400263 const uint8_t *pixelData = NULL;
264 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
265 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700266 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400267 return error;
268 }
269
270 if (pixelData != NULL)
271 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500272 ImageD3D *image = getImage(index);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500273 ASSERT(image);
274
275 gl::Error error = image->loadCompressedData(area, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400276 if (error.isError())
277 {
278 return error;
279 }
280
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700281 mDirtyImages = true;
282 }
283
Geoff Langb5348332014-09-02 13:16:34 -0400284 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700285}
286
287bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
288{
289 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
290}
291
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500292gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
Geoff Langc2e75af2015-01-05 14:26:24 -0500293 GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400295 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700296 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
297 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400298 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700299 }
300
301 // In order to perform the fast copy through the shader, we must have the right format, and be able
302 // to create a render target.
303 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
304
Jacek Cabana5521de2014-10-01 17:23:46 +0200305 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700306
Geoff Langae5122c2014-08-27 14:08:43 -0400307 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
308 if (error.isError())
309 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400310 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400311 }
312
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400313 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700314}
315
316GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
317{
318 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
319 {
320 // Maximum number of levels
321 return gl::log2(std::max(std::max(width, height), depth)) + 1;
322 }
323 else
324 {
325 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
326 return 1;
327 }
328}
329
330int TextureD3D::mipLevels() const
331{
332 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
333}
334
Jamie Madill98553e32014-09-30 16:33:50 -0400335TextureStorage *TextureD3D::getStorage()
336{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400337 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400338 return mTexStorage;
339}
340
Geoff Langb4dedf32015-01-05 14:08:53 -0500341ImageD3D *TextureD3D::getBaseLevelImage() const
Jamie Madill3269bcb2014-09-30 16:33:52 -0400342{
343 return getImage(getImageIndex(0, 0));
344}
345
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400346gl::Error TextureD3D::generateMipmaps()
Jamie Madill4aa79e12014-09-29 10:46:14 -0400347{
Jamie Madill9aca0592014-10-06 16:26:59 -0400348 GLint mipCount = mipLevels();
349
350 if (mipCount == 1)
351 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400352 return gl::Error(GL_NO_ERROR); // no-op
Jamie Madill9aca0592014-10-06 16:26:59 -0400353 }
354
Austin Kinross215b37a2014-12-22 12:56:07 -0800355 if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
356 {
357 // Switch to using the mipmapped texture.
358 gl::Error error = getNativeTexture()->useLevelZeroWorkaroundTexture(false);
359 if (error.isError())
360 {
361 return error;
362 }
363 }
364
Austin Kinross62815bf2015-01-15 16:32:36 -0800365 // Set up proper mipmap chain in our Image array.
366 initMipmapsImages();
367
Jamie Madill4aa79e12014-09-29 10:46:14 -0400368 // We know that all layers have the same dimension, for the texture to be complete
369 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400370
Jamie Madill9aca0592014-10-06 16:26:59 -0400371 // When making mipmaps with the setData workaround enabled, the texture storage has
372 // the image data already. For non-render-target storage, we have to pull it out into
373 // an image layer.
374 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
375 {
376 if (!mTexStorage->isRenderTarget())
377 {
378 // Copy from the storage mip 0 to Image mip 0
379 for (GLint layer = 0; layer < layerCount; ++layer)
380 {
381 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400382
Geoff Langb4dedf32015-01-05 14:08:53 -0500383 ImageD3D *image = getImage(srcIndex);
Jamie Madill9aca0592014-10-06 16:26:59 -0400384 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500385 gl::Offset offset(0, 0, 0);
386 gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400387 if (error.isError())
388 {
389 return error;
390 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400391 }
392 }
393 else
394 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400395 gl::Error error = updateStorage();
396 if (error.isError())
397 {
398 return error;
399 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400400 }
401 }
402
Austin Kinross215b37a2014-12-22 12:56:07 -0800403 // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to zeroMaxLodWorkaround.
404 // The restriction is because Feature Level 9_3 can't create SRVs on individual levels of the texture.
405 // As a result, even if the storage is a rendertarget, we can't use the GPU to generate the mipmaps without further work.
406 // The D3D9 renderer works around this by copying each level of the texture into its own single-layer GPU texture (in Blit9::boxFilter).
407 // Feature Level 9_3 could do something similar, or it could continue to use CPU-side mipmap generation, or something else.
408 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && !(mRenderer->getWorkarounds().zeroMaxLodWorkaround));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400409
410 for (GLint layer = 0; layer < layerCount; ++layer)
411 {
412 for (GLint mip = 1; mip < mipCount; ++mip)
413 {
414 ASSERT(getLayerCount(mip) == layerCount);
415
416 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
417 gl::ImageIndex destIndex = getImageIndex(mip, layer);
418
419 if (renderableStorage)
420 {
421 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400422 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
423 if (error.isError())
424 {
425 return error;
426 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400427 }
428 else
429 {
430 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400431 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
432 if (error.isError())
433 {
434 return error;
435 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400436 }
437 }
438 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400439
440 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400441}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442
Jamie Madill135570a2014-09-30 16:33:51 -0400443bool TextureD3D::isBaseImageZeroSize() const
444{
Geoff Langb4dedf32015-01-05 14:08:53 -0500445 ImageD3D *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400446
447 if (!baseImage || baseImage->getWidth() <= 0)
448 {
449 return true;
450 }
451
Geoff Lang691e58c2014-12-19 17:03:25 -0500452 if (!gl::IsCubeMapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
Jamie Madill135570a2014-09-30 16:33:51 -0400453 {
454 return true;
455 }
456
457 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
458 {
459 return true;
460 }
461
462 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
463 {
464 return true;
465 }
466
467 return false;
468}
469
Geoff Langef7b0162014-09-04 13:29:23 -0400470gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400471{
Geoff Langef7b0162014-09-04 13:29:23 -0400472 gl::Error error = initializeStorage(true);
473 if (error.isError())
474 {
475 return error;
476 }
Jamie Madill135570a2014-09-30 16:33:51 -0400477
478 if (!isBaseImageZeroSize())
479 {
480 ASSERT(mTexStorage);
481 if (!mTexStorage->isRenderTarget())
482 {
Geoff Langef7b0162014-09-04 13:29:23 -0400483 TextureStorage *newRenderTargetStorage = NULL;
484 error = createCompleteStorage(true, &newRenderTargetStorage);
485 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400486 {
Geoff Langef7b0162014-09-04 13:29:23 -0400487 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400488 }
489
Geoff Langef7b0162014-09-04 13:29:23 -0400490 error = mTexStorage->copyToStorage(newRenderTargetStorage);
491 if (error.isError())
492 {
493 SafeDelete(newRenderTargetStorage);
494 return error;
495 }
496
497 error = setCompleteTexStorage(newRenderTargetStorage);
498 if (error.isError())
499 {
500 SafeDelete(newRenderTargetStorage);
501 return error;
502 }
Jamie Madill135570a2014-09-30 16:33:51 -0400503 }
504 }
505
Geoff Langef7b0162014-09-04 13:29:23 -0400506 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400507}
508
Jamie Madille76bdda2014-10-20 17:13:52 -0400509bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
510{
Geoff Langb4dedf32015-01-05 14:08:53 -0500511 ImageD3D *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400512 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
513 return (image->isRenderableFormat() && levelsComplete);
514}
515
Jamie Madill710e5772014-10-20 17:13:53 -0400516gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
517{
518 if (mTexStorage)
519 {
520 ASSERT(isValidIndex(index));
Geoff Langb4dedf32015-01-05 14:08:53 -0500521 ImageD3D *image = getImage(index);
522 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Jamie Madill710e5772014-10-20 17:13:53 -0400523 if (error.isError())
524 {
525 return error;
526 }
527
528 image->markClean();
529 }
530
531 return gl::Error(GL_NO_ERROR);
532}
533
Jamie Madill93e13fb2014-11-06 15:27:25 -0500534TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400535 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536{
537 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
538 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500539 mImageArray[i] = renderer->createImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540 }
541}
542
543TextureD3D_2D::~TextureD3D_2D()
544{
Austin Kinross69822602014-08-12 15:51:37 -0700545 // Delete the Images before the TextureStorage.
546 // Images might be relying on the TextureStorage for some of their data.
547 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700548 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
549 {
550 delete mImageArray[i];
551 }
Austin Kinross69822602014-08-12 15:51:37 -0700552
553 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700554}
555
Geoff Langb4dedf32015-01-05 14:08:53 -0500556ImageD3D *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700557{
558 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700559 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560 return mImageArray[level];
561}
562
Geoff Langb4dedf32015-01-05 14:08:53 -0500563ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -0400564{
565 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400566 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400567 ASSERT(index.type == GL_TEXTURE_2D);
568 return mImageArray[index.mipIndex];
569}
570
Brandon Jonescef06ff2014-08-05 13:27:48 -0700571GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700572{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700573 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
574 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575}
576
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700577GLsizei TextureD3D_2D::getWidth(GLint level) const
578{
579 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
580 return mImageArray[level]->getWidth();
581 else
582 return 0;
583}
584
585GLsizei TextureD3D_2D::getHeight(GLint level) const
586{
587 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
588 return mImageArray[level]->getHeight();
589 else
590 return 0;
591}
592
593GLenum TextureD3D_2D::getInternalFormat(GLint level) const
594{
595 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
596 return mImageArray[level]->getInternalFormat();
597 else
598 return GL_NONE;
599}
600
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700601bool TextureD3D_2D::isDepth(GLint level) const
602{
Geoff Lang5d601382014-07-22 15:14:06 -0400603 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604}
605
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500606gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
607 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500609 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700610
Geoff Lang5d601382014-07-22 15:14:06 -0400611 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
612
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 bool fastUnpacked = false;
614
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500615 redefineImage(level, sizedInternalFormat, size);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700616
Jamie Madillba6bc952014-10-06 10:56:22 -0400617 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
618
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 // Attempt a fast gpu copy of the pixel data to the surface
620 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
621 {
622 // Will try to create RT storage if it does not exist
Geoff Langc2e75af2015-01-05 14:26:24 -0500623 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -0400624 gl::Error error = getRenderTarget(index, &destRenderTarget);
625 if (error.isError())
626 {
627 return error;
628 }
629
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
631
Geoff Lang64f23f62014-09-10 14:40:12 -0400632 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
633 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400635 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400637
638 // Ensure we don't overwrite our newly initialized data
639 mImageArray[level]->markClean();
640
641 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700642 }
643
644 if (!fastUnpacked)
645 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500646 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400647 if (error.isError())
648 {
649 return error;
650 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400652
653 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654}
655
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500656gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
657 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700658{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500659 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700660
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700661 bool fastUnpacked = false;
662
Jamie Madillac7579c2014-09-17 16:59:33 -0400663 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700664 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
665 {
Geoff Langc2e75af2015-01-05 14:26:24 -0500666 RenderTargetD3D *renderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -0400667 gl::Error error = getRenderTarget(index, &renderTarget);
668 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400670 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400672
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500673 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -0400674 if (error.isError())
675 {
676 return error;
677 }
678
679 // Ensure we don't overwrite our newly initialized data
680 mImageArray[level]->markClean();
681
682 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683 }
684
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400685 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500687 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400689
690 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691}
692
Brandon Jonescef06ff2014-08-05 13:27:48 -0700693
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500694gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
695 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
696{
697 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
698
699 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
700 redefineImage(level, internalFormat, size);
701
702 return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels);
703}
704
705gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
706 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
707{
708 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
709
710 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
711 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -0400712 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700713 {
Geoff Langb5348332014-09-02 13:16:34 -0400714 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700715 }
Geoff Langb5348332014-09-02 13:16:34 -0400716
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500717 return commitRegion(index, area);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700718}
719
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500720gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
721 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700722{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700723 ASSERT(target == GL_TEXTURE_2D);
724
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500725 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
726 redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1));
Brandon Jonescef06ff2014-08-05 13:27:48 -0700727
Jamie Madille76bdda2014-10-20 17:13:52 -0400728 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500729 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400730
Austin Kinross62815bf2015-01-15 16:32:36 -0800731 // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
732 // so we should use the non-rendering copy path.
733 if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700734 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500735 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400736 if (error.isError())
737 {
738 return error;
739 }
740
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700741 mDirtyImages = true;
742 }
743 else
744 {
Geoff Langef7b0162014-09-04 13:29:23 -0400745 gl::Error error = ensureRenderTarget();
746 if (error.isError())
747 {
748 return error;
749 }
750
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700751 mImageArray[level]->markClean();
752
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500753 if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700754 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500755 gl::Error error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400756 if (error.isError())
757 {
758 return error;
759 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700760 }
761 }
Geoff Langef7b0162014-09-04 13:29:23 -0400762
763 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700764}
765
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500766gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
767 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700768{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500769 ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700770
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700771 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
772 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700773
Jamie Madille76bdda2014-10-20 17:13:52 -0400774 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400775
Austin Kinross62815bf2015-01-15 16:32:36 -0800776 // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
777 // so we should use the non-rendering copy path.
778 if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700779 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500780 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400781 if (error.isError())
782 {
783 return error;
784 }
785
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700786 mDirtyImages = true;
787 }
788 else
789 {
Geoff Langef7b0162014-09-04 13:29:23 -0400790 gl::Error error = ensureRenderTarget();
791 if (error.isError())
792 {
793 return error;
794 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700795
796 if (isValidLevel(level))
797 {
Geoff Langef7b0162014-09-04 13:29:23 -0400798 error = updateStorageLevel(level);
799 if (error.isError())
800 {
801 return error;
802 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700803
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500804 error = mRenderer->copyImage2D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -0400805 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500806 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400807 if (error.isError())
808 {
809 return error;
810 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700811 }
812 }
Geoff Langef7b0162014-09-04 13:29:23 -0400813
814 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700815}
816
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500817gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500819 ASSERT(GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700820
Geoff Lang8fed1f72015-01-09 11:09:33 -0500821 for (size_t level = 0; level < levels; level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700822 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500823 gl::Extents levelSize(std::max(1, size.width >> level),
824 std::max(1, size.height >> level),
825 1);
826 mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700827 }
828
829 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
830 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500831 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700832 }
833
Geoff Lang1f8532b2014-09-05 09:46:13 -0400834 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400835 bool renderTarget = IsRenderTargetUsage(mUsage);
Austin Kinross215b37a2014-12-22 12:56:07 -0800836 TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400837
838 gl::Error error = setCompleteTexStorage(storage);
839 if (error.isError())
840 {
841 SafeDelete(storage);
842 return error;
843 }
844
845 mImmutable = true;
846
847 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700848}
849
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700850void TextureD3D_2D::bindTexImage(egl::Surface *surface)
851{
852 GLenum internalformat = surface->getFormat();
853
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500854 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
855 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700856
857 if (mTexStorage)
858 {
859 SafeDelete(mTexStorage);
860 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400861
Jamie Madillfb0580a2014-11-27 14:03:52 -0500862 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
863 ASSERT(surfaceD3D);
864
865 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866
867 mDirtyImages = true;
868}
869
870void TextureD3D_2D::releaseTexImage()
871{
872 if (mTexStorage)
873 {
874 SafeDelete(mTexStorage);
875 }
876
877 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
878 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500879 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700880 }
881}
882
Jamie Madill4aa79e12014-09-29 10:46:14 -0400883void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700885 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700886 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700887 for (int level = 1; level < levelCount; level++)
888 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500889 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
890 std::max(getBaseLevelHeight() >> level, 1),
891 1);
892
893 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700894 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700895}
896
Jamie Madillac7579c2014-09-17 16:59:33 -0400897unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700898{
Jamie Madillac7579c2014-09-17 16:59:33 -0400899 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400900 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700901}
902
Geoff Langc2e75af2015-01-05 14:26:24 -0500903gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700904{
Jamie Madillac7579c2014-09-17 16:59:33 -0400905 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700906
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700907 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400908 gl::Error error = ensureRenderTarget();
909 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700910 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400911 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700912 }
913
Geoff Langef7b0162014-09-04 13:29:23 -0400914 error = updateStorageLevel(index.mipIndex);
915 if (error.isError())
916 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400917 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400918 }
919
Geoff Lang64f23f62014-09-10 14:40:12 -0400920 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700921}
922
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700923bool TextureD3D_2D::isValidLevel(int level) const
924{
925 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
926}
927
928bool TextureD3D_2D::isLevelComplete(int level) const
929{
930 if (isImmutable())
931 {
932 return true;
933 }
934
Geoff Langb4dedf32015-01-05 14:08:53 -0500935 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700936
937 GLsizei width = baseImage->getWidth();
938 GLsizei height = baseImage->getHeight();
939
940 if (width <= 0 || height <= 0)
941 {
942 return false;
943 }
944
945 // The base image level is complete if the width and height are positive
946 if (level == 0)
947 {
948 return true;
949 }
950
951 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700952 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700953
954 if (image->getInternalFormat() != baseImage->getInternalFormat())
955 {
956 return false;
957 }
958
959 if (image->getWidth() != std::max(1, width >> level))
960 {
961 return false;
962 }
963
964 if (image->getHeight() != std::max(1, height >> level))
965 {
966 return false;
967 }
968
969 return true;
970}
971
Jamie Madille76bdda2014-10-20 17:13:52 -0400972bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
973{
974 return isLevelComplete(index.mipIndex);
975}
976
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700977// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400978gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700979{
980 // Only initialize the first time this texture is used as a render target or shader resource
981 if (mTexStorage)
982 {
Geoff Langef7b0162014-09-04 13:29:23 -0400983 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700984 }
985
986 // do not attempt to create storage for nonexistant data
987 if (!isLevelComplete(0))
988 {
Geoff Langef7b0162014-09-04 13:29:23 -0400989 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990 }
991
992 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
993
Geoff Langef7b0162014-09-04 13:29:23 -0400994 TextureStorage *storage = NULL;
995 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
996 if (error.isError())
997 {
998 return error;
999 }
1000
1001 error = setCompleteTexStorage(storage);
1002 if (error.isError())
1003 {
1004 SafeDelete(storage);
1005 return error;
1006 }
1007
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001008 ASSERT(mTexStorage);
1009
1010 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001011 error = updateStorage();
1012 if (error.isError())
1013 {
1014 return error;
1015 }
1016
1017 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001018}
1019
Geoff Langef7b0162014-09-04 13:29:23 -04001020gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001021{
1022 GLsizei width = getBaseLevelWidth();
1023 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001024 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001025
1026 ASSERT(width > 0 && height > 0);
1027
1028 // use existing storage level count, when previously specified by TexStorage*D
1029 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1030
Austin Kinross215b37a2014-12-22 12:56:07 -08001031 bool hintLevelZeroOnly = false;
1032 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1033 {
1034 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
1035 // Otherwise, it should use the level-zero-only texture.
1036 hintLevelZeroOnly = true;
Austin Kinross62815bf2015-01-15 16:32:36 -08001037 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
Austin Kinross215b37a2014-12-22 12:56:07 -08001038 {
1039 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
Austin Kinross215b37a2014-12-22 12:56:07 -08001040 }
1041 }
1042
Geoff Langef7b0162014-09-04 13:29:23 -04001043 // TODO(geofflang): Determine if the texture creation succeeded
Austin Kinross215b37a2014-12-22 12:56:07 -08001044 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly);
Geoff Langef7b0162014-09-04 13:29:23 -04001045
1046 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001047}
1048
Geoff Langef7b0162014-09-04 13:29:23 -04001049gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001050{
Geoff Langef7b0162014-09-04 13:29:23 -04001051 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001052 {
Geoff Langef7b0162014-09-04 13:29:23 -04001053 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001054 {
Geoff Langef7b0162014-09-04 13:29:23 -04001055 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1056 if (error.isError())
1057 {
1058 return error;
1059 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001060 }
1061 }
1062
Geoff Langef7b0162014-09-04 13:29:23 -04001063 SafeDelete(mTexStorage);
1064 mTexStorage = newCompleteTexStorage;
1065
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001066 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001067
1068 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001069}
1070
Geoff Langef7b0162014-09-04 13:29:23 -04001071gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001072{
1073 ASSERT(mTexStorage != NULL);
1074 GLint storageLevels = mTexStorage->getLevelCount();
1075 for (int level = 0; level < storageLevels; level++)
1076 {
1077 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1078 {
Geoff Langef7b0162014-09-04 13:29:23 -04001079 gl::Error error = updateStorageLevel(level);
1080 if (error.isError())
1081 {
1082 return error;
1083 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001084 }
1085 }
Geoff Langef7b0162014-09-04 13:29:23 -04001086
1087 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001088}
1089
Geoff Langef7b0162014-09-04 13:29:23 -04001090gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001091{
1092 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1093 ASSERT(isLevelComplete(level));
1094
1095 if (mImageArray[level]->isDirty())
1096 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001097 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1098 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001099 gl::Error error = commitRegion(index, region);
1100 if (error.isError())
1101 {
1102 return error;
1103 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001104 }
Geoff Langef7b0162014-09-04 13:29:23 -04001105
1106 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001107}
1108
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001109void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001110{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001111 ASSERT(size.depth == 1);
1112
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001113 // If there currently is a corresponding storage texture image, it has these parameters
1114 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1115 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1116 const GLenum storageFormat = getBaseLevelInternalFormat();
1117
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001118 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001119
1120 if (mTexStorage)
1121 {
1122 const int storageLevels = mTexStorage->getLevelCount();
1123
1124 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001125 size.width != storageWidth ||
1126 size.height != storageHeight ||
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001127 internalformat != storageFormat) // Discard mismatched storage
1128 {
1129 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1130 {
1131 mImageArray[i]->markDirty();
1132 }
1133
1134 SafeDelete(mTexStorage);
1135 mDirtyImages = true;
1136 }
1137 }
1138}
1139
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001140gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1141{
1142 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1143}
Brandon Jones0511e802014-07-14 16:27:26 -07001144
Jamie Madillcb83dc12014-09-29 10:46:12 -04001145gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1146{
1147 // "layer" does not apply to 2D Textures.
1148 return gl::ImageIndex::Make2D(mip);
1149}
1150
Jamie Madill710e5772014-10-20 17:13:53 -04001151bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1152{
1153 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1154 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1155}
1156
Jamie Madill93e13fb2014-11-06 15:27:25 -05001157TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001158 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001159{
1160 for (int i = 0; i < 6; i++)
1161 {
1162 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1163 {
Geoff Langb4dedf32015-01-05 14:08:53 -05001164 mImageArray[i][j] = renderer->createImage();
Brandon Jones0511e802014-07-14 16:27:26 -07001165 }
1166 }
1167}
1168
1169TextureD3D_Cube::~TextureD3D_Cube()
1170{
Austin Kinross69822602014-08-12 15:51:37 -07001171 // Delete the Images before the TextureStorage.
1172 // Images might be relying on the TextureStorage for some of their data.
1173 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -07001174 for (int i = 0; i < 6; i++)
1175 {
1176 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1177 {
1178 SafeDelete(mImageArray[i][j]);
1179 }
1180 }
Austin Kinross69822602014-08-12 15:51:37 -07001181
1182 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001183}
1184
Geoff Langb4dedf32015-01-05 14:08:53 -05001185ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001186{
1187 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001188 ASSERT(layer >= 0 && layer < 6);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001189 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001190}
1191
Geoff Langb4dedf32015-01-05 14:08:53 -05001192ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04001193{
1194 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001195 ASSERT(index.layerIndex >= 0 && index.layerIndex < 6);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001196 return mImageArray[index.layerIndex][index.mipIndex];
1197}
1198
Brandon Jonescef06ff2014-08-05 13:27:48 -07001199GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001200{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001201 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1202 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001203}
1204
Brandon Jonescef06ff2014-08-05 13:27:48 -07001205GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001206{
1207 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001208 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001209 else
1210 return GL_NONE;
1211}
1212
Brandon Jonescef06ff2014-08-05 13:27:48 -07001213bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001214{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001215 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001216}
1217
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001218gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1219 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001220{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001221 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001222
Geoff Lang5d601382014-07-22 15:14:06 -04001223 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001224 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001225
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001226 redefineImage(index.layerIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001227
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001228 return TextureD3D::setImage(index, type, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001229}
1230
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001231gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1232 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001233{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001234 ASSERT(area.depth == 1 && area.z == 0);
1235
1236 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
1237 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
1238}
1239
1240gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1241 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1242{
1243 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001244
Brandon Jones0511e802014-07-14 16:27:26 -07001245 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Geoff Lang691e58c2014-12-19 17:03:25 -05001246 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001247
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001248 redefineImage(faceIndex, level, internalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001249
Jamie Madillfeda4d22014-09-17 13:03:29 -04001250 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001251 return TextureD3D::setCompressedImage(index, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001252}
1253
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001254gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1255 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001256{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001257 ASSERT(area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001258
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001259 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001260
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001261 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001262 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001263 {
Geoff Langb5348332014-09-02 13:16:34 -04001264 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001265 }
Geoff Langb5348332014-09-02 13:16:34 -04001266
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001267 return commitRegion(index, area);
Brandon Jones0511e802014-07-14 16:27:26 -07001268}
1269
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001270gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1271 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001272{
Geoff Lang691e58c2014-12-19 17:03:25 -05001273 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001274 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04001275
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001276 gl::Extents size(sourceArea.width, sourceArea.height, 1);
1277 redefineImage(faceIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001278
Jamie Madille76bdda2014-10-20 17:13:52 -04001279 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001280 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001281
Jamie Madille76bdda2014-10-20 17:13:52 -04001282 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001283 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001284 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001285 if (error.isError())
1286 {
1287 return error;
1288 }
1289
Brandon Jones0511e802014-07-14 16:27:26 -07001290 mDirtyImages = true;
1291 }
1292 else
1293 {
Geoff Langef7b0162014-09-04 13:29:23 -04001294 gl::Error error = ensureRenderTarget();
1295 if (error.isError())
1296 {
1297 return error;
1298 }
1299
Brandon Jones0511e802014-07-14 16:27:26 -07001300 mImageArray[faceIndex][level]->markClean();
1301
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001302 ASSERT(size.width == size.height);
Brandon Jones0511e802014-07-14 16:27:26 -07001303
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001304 if (size.width > 0 && isValidFaceLevel(faceIndex, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001305 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001306 error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001307 if (error.isError())
1308 {
1309 return error;
1310 }
Brandon Jones0511e802014-07-14 16:27:26 -07001311 }
1312 }
Geoff Langef7b0162014-09-04 13:29:23 -04001313
1314 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001315}
1316
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001317gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1318 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001319{
Geoff Lang691e58c2014-12-19 17:03:25 -05001320 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001321
Jamie Madille76bdda2014-10-20 17:13:52 -04001322 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001323
Jamie Madille76bdda2014-10-20 17:13:52 -04001324 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001325 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001326 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001327 if (error.isError())
1328 {
1329 return error;
1330 }
1331
Brandon Jones0511e802014-07-14 16:27:26 -07001332 mDirtyImages = true;
1333 }
1334 else
1335 {
Geoff Langef7b0162014-09-04 13:29:23 -04001336 gl::Error error = ensureRenderTarget();
1337 if (error.isError())
1338 {
1339 return error;
1340 }
Brandon Jones0511e802014-07-14 16:27:26 -07001341
1342 if (isValidFaceLevel(faceIndex, level))
1343 {
Geoff Langef7b0162014-09-04 13:29:23 -04001344 error = updateStorageFaceLevel(faceIndex, level);
1345 if (error.isError())
1346 {
1347 return error;
1348 }
Brandon Jones0511e802014-07-14 16:27:26 -07001349
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001350 error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1351 destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001352 if (error.isError())
1353 {
1354 return error;
1355 }
Brandon Jones0511e802014-07-14 16:27:26 -07001356 }
1357 }
Geoff Langef7b0162014-09-04 13:29:23 -04001358
1359 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001360}
1361
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001362gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001363{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001364 ASSERT(size.width == size.height);
1365 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001366
Geoff Lang8fed1f72015-01-09 11:09:33 -05001367 for (size_t level = 0; level < levels; level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001368 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001369 GLsizei mipSize = std::max(1, size.width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001370 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1371 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001372 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001373 }
1374 }
1375
1376 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1377 {
1378 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1379 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001380 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001381 }
1382 }
1383
Geoff Lang1f8532b2014-09-05 09:46:13 -04001384 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001385 bool renderTarget = IsRenderTargetUsage(mUsage);
Austin Kinross62815bf2015-01-15 16:32:36 -08001386
1387 TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001388
1389 gl::Error error = setCompleteTexStorage(storage);
1390 if (error.isError())
1391 {
1392 SafeDelete(storage);
1393 return error;
1394 }
1395
1396 mImmutable = true;
1397
1398 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001399}
1400
Brandon Jones0511e802014-07-14 16:27:26 -07001401// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1402bool TextureD3D_Cube::isCubeComplete() const
1403{
1404 int baseWidth = getBaseLevelWidth();
1405 int baseHeight = getBaseLevelHeight();
1406 GLenum baseFormat = getBaseLevelInternalFormat();
1407
1408 if (baseWidth <= 0 || baseWidth != baseHeight)
1409 {
1410 return false;
1411 }
1412
1413 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1414 {
1415 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1416
1417 if (faceBaseImage.getWidth() != baseWidth ||
1418 faceBaseImage.getHeight() != baseHeight ||
1419 faceBaseImage.getInternalFormat() != baseFormat )
1420 {
1421 return false;
1422 }
1423 }
1424
1425 return true;
1426}
1427
Brandon Jones6053a522014-07-25 16:22:09 -07001428void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1429{
1430 UNREACHABLE();
1431}
1432
1433void TextureD3D_Cube::releaseTexImage()
1434{
1435 UNREACHABLE();
1436}
1437
1438
Jamie Madill4aa79e12014-09-29 10:46:14 -04001439void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001440{
1441 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1442 int levelCount = mipLevels();
1443 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1444 {
1445 for (int level = 1; level < levelCount; level++)
1446 {
1447 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001448 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1449 gl::Extents(faceLevelSize, faceLevelSize, 1));
Brandon Jones0511e802014-07-14 16:27:26 -07001450 }
1451 }
Brandon Jones0511e802014-07-14 16:27:26 -07001452}
1453
Jamie Madillac7579c2014-09-17 16:59:33 -04001454unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001455{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001456 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001457}
1458
Geoff Langc2e75af2015-01-05 14:26:24 -05001459gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001460{
Geoff Lang691e58c2014-12-19 17:03:25 -05001461 ASSERT(gl::IsCubeMapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001462
1463 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001464 gl::Error error = ensureRenderTarget();
1465 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001466 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001467 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001468 }
1469
Geoff Langef7b0162014-09-04 13:29:23 -04001470 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1471 if (error.isError())
1472 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001473 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001474 }
1475
Geoff Lang64f23f62014-09-10 14:40:12 -04001476 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001477}
1478
Geoff Langef7b0162014-09-04 13:29:23 -04001479gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001480{
1481 // Only initialize the first time this texture is used as a render target or shader resource
1482 if (mTexStorage)
1483 {
Geoff Langef7b0162014-09-04 13:29:23 -04001484 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001485 }
1486
1487 // do not attempt to create storage for nonexistant data
1488 if (!isFaceLevelComplete(0, 0))
1489 {
Geoff Langef7b0162014-09-04 13:29:23 -04001490 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001491 }
1492
1493 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1494
Geoff Langef7b0162014-09-04 13:29:23 -04001495 TextureStorage *storage = NULL;
1496 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1497 if (error.isError())
1498 {
1499 return error;
1500 }
1501
1502 error = setCompleteTexStorage(storage);
1503 if (error.isError())
1504 {
1505 SafeDelete(storage);
1506 return error;
1507 }
1508
Brandon Jones0511e802014-07-14 16:27:26 -07001509 ASSERT(mTexStorage);
1510
1511 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001512 error = updateStorage();
1513 if (error.isError())
1514 {
1515 return error;
1516 }
1517
1518 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001519}
1520
Geoff Langef7b0162014-09-04 13:29:23 -04001521gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001522{
1523 GLsizei size = getBaseLevelWidth();
1524
1525 ASSERT(size > 0);
1526
1527 // use existing storage level count, when previously specified by TexStorage*D
1528 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1529
Austin Kinross62815bf2015-01-15 16:32:36 -08001530 bool hintLevelZeroOnly = false;
1531 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1532 {
1533 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with.
1534 // Otherwise, it should use the level-zero-only texture.
1535 hintLevelZeroOnly = true;
1536 for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++)
1537 {
1538 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1539 {
1540 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level));
1541 }
1542 }
1543 }
1544
Geoff Langef7b0162014-09-04 13:29:23 -04001545 // TODO (geofflang): detect if storage creation succeeded
Austin Kinross62815bf2015-01-15 16:32:36 -08001546 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly);
Geoff Langef7b0162014-09-04 13:29:23 -04001547
1548 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001549}
1550
Geoff Langef7b0162014-09-04 13:29:23 -04001551gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001552{
Geoff Langef7b0162014-09-04 13:29:23 -04001553 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001554 {
1555 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1556 {
Geoff Langef7b0162014-09-04 13:29:23 -04001557 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001558 {
Geoff Langef7b0162014-09-04 13:29:23 -04001559 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1560 if (error.isError())
1561 {
1562 return error;
1563 }
Brandon Jones0511e802014-07-14 16:27:26 -07001564 }
1565 }
1566 }
1567
Geoff Langef7b0162014-09-04 13:29:23 -04001568 SafeDelete(mTexStorage);
1569 mTexStorage = newCompleteTexStorage;
1570
Brandon Jones0511e802014-07-14 16:27:26 -07001571 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001572 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001573}
1574
Geoff Langef7b0162014-09-04 13:29:23 -04001575gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001576{
1577 ASSERT(mTexStorage != NULL);
1578 GLint storageLevels = mTexStorage->getLevelCount();
1579 for (int face = 0; face < 6; face++)
1580 {
1581 for (int level = 0; level < storageLevels; level++)
1582 {
1583 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1584 {
Geoff Langef7b0162014-09-04 13:29:23 -04001585 gl::Error error = updateStorageFaceLevel(face, level);
1586 if (error.isError())
1587 {
1588 return error;
1589 }
Brandon Jones0511e802014-07-14 16:27:26 -07001590 }
1591 }
1592 }
Geoff Langef7b0162014-09-04 13:29:23 -04001593
1594 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001595}
1596
Brandon Jones0511e802014-07-14 16:27:26 -07001597bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1598{
1599 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1600}
1601
Brandon Jones0511e802014-07-14 16:27:26 -07001602bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1603{
1604 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1605
1606 if (isImmutable())
1607 {
1608 return true;
1609 }
1610
1611 int baseSize = getBaseLevelWidth();
1612
1613 if (baseSize <= 0)
1614 {
1615 return false;
1616 }
1617
1618 // "isCubeComplete" checks for base level completeness and we must call that
1619 // to determine if any face at level 0 is complete. We omit that check here
1620 // to avoid re-checking cube-completeness for every face at level 0.
1621 if (level == 0)
1622 {
1623 return true;
1624 }
1625
1626 // Check that non-zero levels are consistent with the base level.
1627 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1628
1629 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1630 {
1631 return false;
1632 }
1633
1634 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1635 {
1636 return false;
1637 }
1638
1639 return true;
1640}
1641
Jamie Madille76bdda2014-10-20 17:13:52 -04001642bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1643{
1644 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1645}
1646
Geoff Langef7b0162014-09-04 13:29:23 -04001647gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001648{
1649 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1650 ImageD3D *image = mImageArray[faceIndex][level];
1651
1652 if (image->isDirty())
1653 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001654 GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001655 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1656 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001657 gl::Error error = commitRegion(index, region);
1658 if (error.isError())
1659 {
1660 return error;
1661 }
Brandon Jones0511e802014-07-14 16:27:26 -07001662 }
Geoff Langef7b0162014-09-04 13:29:23 -04001663
1664 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001665}
1666
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001667void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001668{
1669 // If there currently is a corresponding storage texture image, it has these parameters
1670 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1671 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1672 const GLenum storageFormat = getBaseLevelInternalFormat();
1673
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001674 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001675
1676 if (mTexStorage)
1677 {
1678 const int storageLevels = mTexStorage->getLevelCount();
1679
1680 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001681 size.width != storageWidth ||
1682 size.height != storageHeight ||
Brandon Jones0511e802014-07-14 16:27:26 -07001683 internalformat != storageFormat) // Discard mismatched storage
1684 {
1685 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1686 {
1687 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1688 {
1689 mImageArray[faceIndex][level]->markDirty();
1690 }
1691 }
1692
1693 SafeDelete(mTexStorage);
1694
1695 mDirtyImages = true;
1696 }
1697 }
1698}
1699
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001700gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1701{
1702 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1703}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001704
Jamie Madillcb83dc12014-09-29 10:46:12 -04001705gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1706{
1707 // The "layer" of the image index corresponds to the cube face
Geoff Lang691e58c2014-12-19 17:03:25 -05001708 return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip);
Jamie Madillcb83dc12014-09-29 10:46:12 -04001709}
1710
Jamie Madill710e5772014-10-20 17:13:53 -04001711bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1712{
Geoff Lang691e58c2014-12-19 17:03:25 -05001713 return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) &&
Jamie Madill710e5772014-10-20 17:13:53 -04001714 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1715}
1716
Jamie Madill93e13fb2014-11-06 15:27:25 -05001717TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001718 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001719{
1720 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1721 {
Geoff Langb4dedf32015-01-05 14:08:53 -05001722 mImageArray[i] = renderer->createImage();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001723 }
1724}
1725
1726TextureD3D_3D::~TextureD3D_3D()
1727{
Austin Kinross69822602014-08-12 15:51:37 -07001728 // Delete the Images before the TextureStorage.
1729 // Images might be relying on the TextureStorage for some of their data.
1730 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones78b1acd2014-07-15 15:33:07 -07001731 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1732 {
1733 delete mImageArray[i];
1734 }
Austin Kinross69822602014-08-12 15:51:37 -07001735
1736 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737}
1738
Geoff Langb4dedf32015-01-05 14:08:53 -05001739ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001740{
1741 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001742 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001743 return mImageArray[level];
1744}
1745
Geoff Langb4dedf32015-01-05 14:08:53 -05001746ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04001747{
1748 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001749 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001750 ASSERT(index.type == GL_TEXTURE_3D);
1751 return mImageArray[index.mipIndex];
1752}
1753
Brandon Jonescef06ff2014-08-05 13:27:48 -07001754GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001755{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001756 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1757 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758}
1759
Brandon Jones78b1acd2014-07-15 15:33:07 -07001760GLsizei TextureD3D_3D::getWidth(GLint level) const
1761{
1762 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1763 return mImageArray[level]->getWidth();
1764 else
1765 return 0;
1766}
1767
1768GLsizei TextureD3D_3D::getHeight(GLint level) const
1769{
1770 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1771 return mImageArray[level]->getHeight();
1772 else
1773 return 0;
1774}
1775
1776GLsizei TextureD3D_3D::getDepth(GLint level) const
1777{
1778 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1779 return mImageArray[level]->getDepth();
1780 else
1781 return 0;
1782}
1783
1784GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1785{
1786 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1787 return mImageArray[level]->getInternalFormat();
1788 else
1789 return GL_NONE;
1790}
1791
1792bool TextureD3D_3D::isDepth(GLint level) const
1793{
Geoff Lang5d601382014-07-22 15:14:06 -04001794 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001795}
1796
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001797gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1798 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001799{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001800 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001801 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1802
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001803 redefineImage(level, sizedInternalFormat, size);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001804
1805 bool fastUnpacked = false;
1806
Jamie Madillba6bc952014-10-06 10:56:22 -04001807 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1808
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
Jamie Madill3c9db122015-01-15 16:36:55 -05001810 if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001811 {
1812 // Will try to create RT storage if it does not exist
Geoff Langc2e75af2015-01-05 14:26:24 -05001813 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -04001814 gl::Error error = getRenderTarget(index, &destRenderTarget);
1815 if (error.isError())
1816 {
1817 return error;
1818 }
1819
Brandon Jones78b1acd2014-07-15 15:33:07 -07001820 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1821
Geoff Lang64f23f62014-09-10 14:40:12 -04001822 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1823 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001825 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001826 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001827
1828 // Ensure we don't overwrite our newly initialized data
1829 mImageArray[level]->markClean();
1830
1831 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001832 }
1833
1834 if (!fastUnpacked)
1835 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001836 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001837 if (error.isError())
1838 {
1839 return error;
1840 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001841 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001842
1843 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844}
1845
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001846gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1847 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001849 ASSERT(target == GL_TEXTURE_3D);
1850
Brandon Jones78b1acd2014-07-15 15:33:07 -07001851 bool fastUnpacked = false;
1852
Jamie Madillac7579c2014-09-17 16:59:33 -04001853 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1854
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1856 if (isFastUnpackable(unpack, getInternalFormat(level)))
1857 {
Geoff Langc2e75af2015-01-05 14:26:24 -05001858 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -04001859 gl::Error error = getRenderTarget(index, &destRenderTarget);
1860 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001862 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001864
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001865 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -04001866 if (error.isError())
1867 {
1868 return error;
1869 }
1870
1871 // Ensure we don't overwrite our newly initialized data
1872 mImageArray[level]->markClean();
1873
1874 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001875 }
1876
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001877 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001878 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001879 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001880 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001881
1882 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001883}
1884
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001885gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1886 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001887{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001888 ASSERT(target == GL_TEXTURE_3D);
1889
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001890 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1891 redefineImage(level, internalFormat, size);
1892
1893 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1894 return TextureD3D::setCompressedImage(index, unpack, pixels);
1895}
1896
1897gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1898 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1899{
1900 ASSERT(target == GL_TEXTURE_3D);
1901
1902 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1903 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001904 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001905 {
Geoff Langb5348332014-09-02 13:16:34 -04001906 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001907 }
Geoff Langb5348332014-09-02 13:16:34 -04001908
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001909 return commitRegion(index, area);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001910}
1911
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001912gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1913 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001914{
1915 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001916 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001917}
1918
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001919gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1920 const gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001921{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001922 ASSERT(target == GL_TEXTURE_3D);
1923
Jamie Madille76bdda2014-10-20 17:13:52 -04001924 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001925
Jamie Madille76bdda2014-10-20 17:13:52 -04001926 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001927 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001928 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001929 if (error.isError())
1930 {
1931 return error;
1932 }
1933
Brandon Jones78b1acd2014-07-15 15:33:07 -07001934 mDirtyImages = true;
1935 }
1936 else
1937 {
Geoff Langef7b0162014-09-04 13:29:23 -04001938 gl::Error error = ensureRenderTarget();
1939 if (error.isError())
1940 {
1941 return error;
1942 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001943
1944 if (isValidLevel(level))
1945 {
Geoff Langef7b0162014-09-04 13:29:23 -04001946 error = updateStorageLevel(level);
1947 if (error.isError())
1948 {
1949 return error;
1950 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001951
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001952 error = mRenderer->copyImage3D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -04001953 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001954 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001955 if (error.isError())
1956 {
1957 return error;
1958 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001959 }
1960 }
Geoff Langef7b0162014-09-04 13:29:23 -04001961
1962 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001963}
1964
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001965gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001966{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001967 ASSERT(target == GL_TEXTURE_3D);
1968
Geoff Lang8fed1f72015-01-09 11:09:33 -05001969 for (size_t level = 0; level < levels; level++)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001970 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001971 gl::Extents levelSize(std::max(1, size.width >> level),
1972 std::max(1, size.height >> level),
1973 std::max(1, size.depth >> level));
1974 mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001975 }
1976
1977 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1978 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001979 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001980 }
1981
Geoff Lang1f8532b2014-09-05 09:46:13 -04001982 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001983 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001984 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001985
1986 gl::Error error = setCompleteTexStorage(storage);
1987 if (error.isError())
1988 {
1989 SafeDelete(storage);
1990 return error;
1991 }
1992
1993 mImmutable = true;
1994
1995 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001996}
1997
Brandon Jones6053a522014-07-25 16:22:09 -07001998void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001999{
Brandon Jones6053a522014-07-25 16:22:09 -07002000 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002001}
2002
Brandon Jones6053a522014-07-25 16:22:09 -07002003void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002004{
Brandon Jones6053a522014-07-25 16:22:09 -07002005 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002006}
2007
Brandon Jones6053a522014-07-25 16:22:09 -07002008
Jamie Madill4aa79e12014-09-29 10:46:14 -04002009void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002010{
2011 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2012 int levelCount = mipLevels();
2013 for (int level = 1; level < levelCount; level++)
2014 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002015 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
2016 std::max(getBaseLevelHeight() >> level, 1),
2017 std::max(getBaseLevelDepth() >> level, 1));
2018 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002019 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020}
2021
Jamie Madillac7579c2014-09-17 16:59:33 -04002022unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002023{
Geoff Langef7b0162014-09-04 13:29:23 -04002024 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002025}
2026
Geoff Langc2e75af2015-01-05 14:26:24 -05002027gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002028{
2029 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002030 gl::Error error = ensureRenderTarget();
2031 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002032 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002033 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002034 }
2035
Jamie Madillac7579c2014-09-17 16:59:33 -04002036 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002037 {
Geoff Langef7b0162014-09-04 13:29:23 -04002038 error = updateStorage();
2039 if (error.isError())
2040 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002041 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002042 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002043 }
2044 else
2045 {
Geoff Langef7b0162014-09-04 13:29:23 -04002046 error = updateStorageLevel(index.mipIndex);
2047 if (error.isError())
2048 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002049 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002050 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002051 }
2052
Geoff Lang64f23f62014-09-10 14:40:12 -04002053 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002054}
2055
Geoff Langef7b0162014-09-04 13:29:23 -04002056gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002057{
2058 // Only initialize the first time this texture is used as a render target or shader resource
2059 if (mTexStorage)
2060 {
Geoff Langef7b0162014-09-04 13:29:23 -04002061 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062 }
2063
2064 // do not attempt to create storage for nonexistant data
2065 if (!isLevelComplete(0))
2066 {
Geoff Langef7b0162014-09-04 13:29:23 -04002067 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002068 }
2069
2070 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2071
Jamie Madill30d6c252014-11-13 10:03:33 -05002072 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002073 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2074 if (error.isError())
2075 {
2076 return error;
2077 }
2078
2079 error = setCompleteTexStorage(storage);
2080 if (error.isError())
2081 {
2082 SafeDelete(storage);
2083 return error;
2084 }
2085
Brandon Jones78b1acd2014-07-15 15:33:07 -07002086 ASSERT(mTexStorage);
2087
2088 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002089 error = updateStorage();
2090 if (error.isError())
2091 {
2092 return error;
2093 }
2094
2095 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002096}
2097
Geoff Langef7b0162014-09-04 13:29:23 -04002098gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099{
2100 GLsizei width = getBaseLevelWidth();
2101 GLsizei height = getBaseLevelHeight();
2102 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002103 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002104
2105 ASSERT(width > 0 && height > 0 && depth > 0);
2106
2107 // use existing storage level count, when previously specified by TexStorage*D
2108 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2109
Geoff Langef7b0162014-09-04 13:29:23 -04002110 // TODO: Verify creation of the storage succeeded
2111 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2112
2113 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002114}
2115
Geoff Langef7b0162014-09-04 13:29:23 -04002116gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002117{
2118 SafeDelete(mTexStorage);
2119 mTexStorage = newCompleteTexStorage;
2120 mDirtyImages = true;
2121
2122 // We do not support managed 3D storage, as that is D3D9/ES2-only
2123 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002124
2125 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002126}
2127
Geoff Langef7b0162014-09-04 13:29:23 -04002128gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002129{
2130 ASSERT(mTexStorage != NULL);
2131 GLint storageLevels = mTexStorage->getLevelCount();
2132 for (int level = 0; level < storageLevels; level++)
2133 {
2134 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2135 {
Geoff Langef7b0162014-09-04 13:29:23 -04002136 gl::Error error = updateStorageLevel(level);
2137 if (error.isError())
2138 {
2139 return error;
2140 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002141 }
2142 }
Geoff Langef7b0162014-09-04 13:29:23 -04002143
2144 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002145}
2146
Brandon Jones78b1acd2014-07-15 15:33:07 -07002147bool TextureD3D_3D::isValidLevel(int level) const
2148{
2149 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2150}
2151
2152bool TextureD3D_3D::isLevelComplete(int level) const
2153{
2154 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2155
2156 if (isImmutable())
2157 {
2158 return true;
2159 }
2160
2161 GLsizei width = getBaseLevelWidth();
2162 GLsizei height = getBaseLevelHeight();
2163 GLsizei depth = getBaseLevelDepth();
2164
2165 if (width <= 0 || height <= 0 || depth <= 0)
2166 {
2167 return false;
2168 }
2169
2170 if (level == 0)
2171 {
2172 return true;
2173 }
2174
2175 ImageD3D *levelImage = mImageArray[level];
2176
2177 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2178 {
2179 return false;
2180 }
2181
2182 if (levelImage->getWidth() != std::max(1, width >> level))
2183 {
2184 return false;
2185 }
2186
2187 if (levelImage->getHeight() != std::max(1, height >> level))
2188 {
2189 return false;
2190 }
2191
2192 if (levelImage->getDepth() != std::max(1, depth >> level))
2193 {
2194 return false;
2195 }
2196
2197 return true;
2198}
2199
Jamie Madille76bdda2014-10-20 17:13:52 -04002200bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2201{
2202 return isLevelComplete(index.mipIndex);
2203}
2204
Geoff Langef7b0162014-09-04 13:29:23 -04002205gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002206{
2207 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2208 ASSERT(isLevelComplete(level));
2209
2210 if (mImageArray[level]->isDirty())
2211 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002212 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2213 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002214 gl::Error error = commitRegion(index, region);
2215 if (error.isError())
2216 {
2217 return error;
2218 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002219 }
Geoff Langef7b0162014-09-04 13:29:23 -04002220
2221 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002222}
2223
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002224void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002225{
2226 // If there currently is a corresponding storage texture image, it has these parameters
2227 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2228 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2229 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2230 const GLenum storageFormat = getBaseLevelInternalFormat();
2231
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002232 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002233
2234 if (mTexStorage)
2235 {
2236 const int storageLevels = mTexStorage->getLevelCount();
2237
2238 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002239 size.width != storageWidth ||
2240 size.height != storageHeight ||
2241 size.depth != storageDepth ||
Brandon Jones78b1acd2014-07-15 15:33:07 -07002242 internalformat != storageFormat) // Discard mismatched storage
2243 {
2244 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2245 {
2246 mImageArray[i]->markDirty();
2247 }
2248
2249 SafeDelete(mTexStorage);
2250 mDirtyImages = true;
2251 }
2252 }
2253}
2254
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002255gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2256{
2257 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2258 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2259}
Brandon Jones142ec422014-07-16 10:31:30 -07002260
Jamie Madillcb83dc12014-09-29 10:46:12 -04002261gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2262{
2263 // The "layer" here does not apply to 3D images. We use one Image per mip.
2264 return gl::ImageIndex::Make3D(mip);
2265}
2266
Jamie Madill710e5772014-10-20 17:13:53 -04002267bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2268{
2269 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2270 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2271}
2272
Jamie Madill93e13fb2014-11-06 15:27:25 -05002273TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002274 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002275{
2276 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2277 {
2278 mLayerCounts[level] = 0;
2279 mImageArray[level] = NULL;
2280 }
2281}
2282
2283TextureD3D_2DArray::~TextureD3D_2DArray()
2284{
Austin Kinross69822602014-08-12 15:51:37 -07002285 // Delete the Images before the TextureStorage.
2286 // Images might be relying on the TextureStorage for some of their data.
2287 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones142ec422014-07-16 10:31:30 -07002288 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002289 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002290}
2291
Geoff Langb4dedf32015-01-05 14:08:53 -05002292ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
Brandon Jones142ec422014-07-16 10:31:30 -07002293{
2294 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002295 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2296 layer < mLayerCounts[level]);
2297 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002298}
2299
Geoff Langb4dedf32015-01-05 14:08:53 -05002300ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04002301{
2302 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002303 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2304 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002305 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002306 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002307}
2308
Brandon Jones142ec422014-07-16 10:31:30 -07002309GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2310{
2311 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2312 return mLayerCounts[level];
2313}
2314
Brandon Jones142ec422014-07-16 10:31:30 -07002315GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2316{
2317 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2318}
2319
2320GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2321{
2322 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2323}
2324
Brandon Jones142ec422014-07-16 10:31:30 -07002325GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2326{
2327 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2328}
2329
2330bool TextureD3D_2DArray::isDepth(GLint level) const
2331{
Geoff Lang5d601382014-07-22 15:14:06 -04002332 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002333}
2334
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002335gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
2336 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002337{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002338 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2339
Geoff Lang5d601382014-07-22 15:14:06 -04002340 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2341
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002342 redefineImage(level, sizedInternalFormat, size);
Brandon Jones142ec422014-07-16 10:31:30 -07002343
Geoff Lang5d601382014-07-22 15:14:06 -04002344 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002345 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002346
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002347 for (int i = 0; i < size.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002348 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002349 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002350 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002351 gl::Error error = TextureD3D::setImage(index, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002352 if (error.isError())
2353 {
2354 return error;
2355 }
Brandon Jones142ec422014-07-16 10:31:30 -07002356 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002357
2358 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002359}
2360
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002361gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
2362 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002363{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002364 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2365
Geoff Lang5d601382014-07-22 15:14:06 -04002366 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002367 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002368
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002369 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002370 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002371 int layer = area.z + i;
2372 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2373
2374 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002375
Jamie Madillfeda4d22014-09-17 13:03:29 -04002376 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002377 gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002378 if (error.isError())
2379 {
2380 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002381 }
2382 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002383
2384 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002385}
2386
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002387gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
2388 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
2389{
2390 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2391
2392 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2393 redefineImage(level, internalFormat, size);
2394
2395 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2396 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1);
2397
2398 for (int i = 0; i < size.depth; i++)
2399 {
2400 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2401
2402 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2403 gl::Error error = TextureD3D::setCompressedImage(index, unpack, layerPixels);
2404 if (error.isError())
2405 {
2406 return error;
2407 }
2408 }
2409
2410 return gl::Error(GL_NO_ERROR);
2411}
2412
2413gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
2414 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002415{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002416 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2417
Geoff Lang5d601382014-07-22 15:14:06 -04002418 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002419 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002420
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002421 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002422 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002423 int layer = area.z + i;
2424 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Brandon Jones142ec422014-07-16 10:31:30 -07002425
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002426 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
2427
2428 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2429 gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, layerPixels);
Geoff Langb5348332014-09-02 13:16:34 -04002430 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002431 {
Geoff Langb5348332014-09-02 13:16:34 -04002432 return error;
2433 }
2434
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002435 error = commitRegion(index, layerArea);
Geoff Langb5348332014-09-02 13:16:34 -04002436 if (error.isError())
2437 {
2438 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002439 }
2440 }
Geoff Langb5348332014-09-02 13:16:34 -04002441
2442 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002443}
2444
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002445gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
2446 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002447{
2448 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002449 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002450}
2451
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002452gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
2453 const gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002454{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002455 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2456
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002457 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002458
Jamie Madille76bdda2014-10-20 17:13:52 -04002459 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002460 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002461 gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
2462 gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04002463 if (error.isError())
2464 {
2465 return error;
2466 }
2467
Brandon Jones142ec422014-07-16 10:31:30 -07002468 mDirtyImages = true;
2469 }
2470 else
2471 {
Geoff Langef7b0162014-09-04 13:29:23 -04002472 gl::Error error = ensureRenderTarget();
2473 if (error.isError())
2474 {
2475 return error;
2476 }
Brandon Jones142ec422014-07-16 10:31:30 -07002477
2478 if (isValidLevel(level))
2479 {
Geoff Langef7b0162014-09-04 13:29:23 -04002480 error = updateStorageLevel(level);
2481 if (error.isError())
2482 {
2483 return error;
2484 }
Brandon Jones142ec422014-07-16 10:31:30 -07002485
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002486 error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2487 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04002488 if (error.isError())
2489 {
2490 return error;
2491 }
Brandon Jones142ec422014-07-16 10:31:30 -07002492 }
2493 }
Geoff Langef7b0162014-09-04 13:29:23 -04002494 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002495}
2496
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002497gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002498{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002499 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2500
Brandon Jones142ec422014-07-16 10:31:30 -07002501 deleteImages();
2502
Geoff Lang8fed1f72015-01-09 11:09:33 -05002503 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
Brandon Jones142ec422014-07-16 10:31:30 -07002504 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002505 gl::Extents levelLayerSize(std::max(1, size.width >> level),
2506 std::max(1, size.height >> level),
2507 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002508
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002509 mLayerCounts[level] = (level < levels ? size.depth : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002510
2511 if (mLayerCounts[level] > 0)
2512 {
2513 // Create new images for this level
2514 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2515
2516 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2517 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002518 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002519 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true);
Brandon Jones142ec422014-07-16 10:31:30 -07002520 }
2521 }
2522 }
2523
Geoff Lang1f8532b2014-09-05 09:46:13 -04002524 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002525 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002526 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002527
2528 gl::Error error = setCompleteTexStorage(storage);
2529 if (error.isError())
2530 {
2531 SafeDelete(storage);
2532 return error;
2533 }
2534
2535 mImmutable = true;
2536
2537 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002538}
2539
Brandon Jones6053a522014-07-25 16:22:09 -07002540void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002541{
Brandon Jones6053a522014-07-25 16:22:09 -07002542 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002543}
2544
Brandon Jones6053a522014-07-25 16:22:09 -07002545void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002546{
Brandon Jones6053a522014-07-25 16:22:09 -07002547 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002548}
2549
Brandon Jones6053a522014-07-25 16:22:09 -07002550
Jamie Madill4aa79e12014-09-29 10:46:14 -04002551void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002552{
2553 int baseWidth = getBaseLevelWidth();
2554 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002555 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002556 GLenum baseFormat = getBaseLevelInternalFormat();
2557
2558 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2559 int levelCount = mipLevels();
2560 for (int level = 1; level < levelCount; level++)
2561 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002562 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
2563 std::max(baseHeight >> level, 1),
2564 baseDepth);
2565 redefineImage(level, baseFormat, levelLayerSize);
Brandon Jones142ec422014-07-16 10:31:30 -07002566 }
Brandon Jones142ec422014-07-16 10:31:30 -07002567}
2568
Jamie Madillac7579c2014-09-17 16:59:33 -04002569unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002570{
Geoff Langef7b0162014-09-04 13:29:23 -04002571 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002572}
2573
Geoff Langc2e75af2015-01-05 14:26:24 -05002574gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002575{
2576 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002577 gl::Error error = ensureRenderTarget();
2578 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002579 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002580 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002581 }
2582
Geoff Langef7b0162014-09-04 13:29:23 -04002583 error = updateStorageLevel(index.mipIndex);
2584 if (error.isError())
2585 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002586 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002587 }
2588
Geoff Lang64f23f62014-09-10 14:40:12 -04002589 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002590}
2591
Geoff Langef7b0162014-09-04 13:29:23 -04002592gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002593{
2594 // Only initialize the first time this texture is used as a render target or shader resource
2595 if (mTexStorage)
2596 {
Geoff Langef7b0162014-09-04 13:29:23 -04002597 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002598 }
2599
2600 // do not attempt to create storage for nonexistant data
2601 if (!isLevelComplete(0))
2602 {
Geoff Langef7b0162014-09-04 13:29:23 -04002603 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002604 }
2605
2606 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2607
Geoff Langef7b0162014-09-04 13:29:23 -04002608 TextureStorage *storage = NULL;
2609 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2610 if (error.isError())
2611 {
2612 return error;
2613 }
2614
2615 error = setCompleteTexStorage(storage);
2616 if (error.isError())
2617 {
2618 SafeDelete(storage);
2619 return error;
2620 }
2621
Brandon Jones142ec422014-07-16 10:31:30 -07002622 ASSERT(mTexStorage);
2623
2624 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002625 error = updateStorage();
2626 if (error.isError())
2627 {
2628 return error;
2629 }
2630
2631 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002632}
2633
Geoff Langef7b0162014-09-04 13:29:23 -04002634gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002635{
2636 GLsizei width = getBaseLevelWidth();
2637 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002638 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002639 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002640
2641 ASSERT(width > 0 && height > 0 && depth > 0);
2642
2643 // use existing storage level count, when previously specified by TexStorage*D
2644 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2645
Geoff Langef7b0162014-09-04 13:29:23 -04002646 // TODO(geofflang): Verify storage creation succeeds
2647 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2648
2649 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002650}
2651
Geoff Langef7b0162014-09-04 13:29:23 -04002652gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002653{
2654 SafeDelete(mTexStorage);
2655 mTexStorage = newCompleteTexStorage;
2656 mDirtyImages = true;
2657
2658 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2659 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002660
2661 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002662}
2663
Geoff Langef7b0162014-09-04 13:29:23 -04002664gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002665{
2666 ASSERT(mTexStorage != NULL);
2667 GLint storageLevels = mTexStorage->getLevelCount();
2668 for (int level = 0; level < storageLevels; level++)
2669 {
2670 if (isLevelComplete(level))
2671 {
Geoff Langef7b0162014-09-04 13:29:23 -04002672 gl::Error error = updateStorageLevel(level);
2673 if (error.isError())
2674 {
2675 return error;
2676 }
Brandon Jones142ec422014-07-16 10:31:30 -07002677 }
2678 }
Geoff Langef7b0162014-09-04 13:29:23 -04002679
2680 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002681}
2682
Brandon Jones142ec422014-07-16 10:31:30 -07002683bool TextureD3D_2DArray::isValidLevel(int level) const
2684{
2685 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2686}
2687
2688bool TextureD3D_2DArray::isLevelComplete(int level) const
2689{
2690 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2691
2692 if (isImmutable())
2693 {
2694 return true;
2695 }
2696
2697 GLsizei width = getBaseLevelWidth();
2698 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002699 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002700
2701 if (width <= 0 || height <= 0 || layers <= 0)
2702 {
2703 return false;
2704 }
2705
2706 if (level == 0)
2707 {
2708 return true;
2709 }
2710
2711 if (getInternalFormat(level) != getInternalFormat(0))
2712 {
2713 return false;
2714 }
2715
2716 if (getWidth(level) != std::max(1, width >> level))
2717 {
2718 return false;
2719 }
2720
2721 if (getHeight(level) != std::max(1, height >> level))
2722 {
2723 return false;
2724 }
2725
Jamie Madill3269bcb2014-09-30 16:33:52 -04002726 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002727 {
2728 return false;
2729 }
2730
2731 return true;
2732}
2733
Jamie Madille76bdda2014-10-20 17:13:52 -04002734bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2735{
2736 return isLevelComplete(index.mipIndex);
2737}
2738
Geoff Langef7b0162014-09-04 13:29:23 -04002739gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002740{
2741 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2742 ASSERT(isLevelComplete(level));
2743
2744 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2745 {
2746 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2747 if (mImageArray[level][layer]->isDirty())
2748 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002749 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2750 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002751 gl::Error error = commitRegion(index, region);
2752 if (error.isError())
2753 {
2754 return error;
2755 }
Brandon Jones142ec422014-07-16 10:31:30 -07002756 }
2757 }
Geoff Langef7b0162014-09-04 13:29:23 -04002758
2759 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002760}
2761
2762void TextureD3D_2DArray::deleteImages()
2763{
2764 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2765 {
2766 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2767 {
2768 delete mImageArray[level][layer];
2769 }
2770 delete[] mImageArray[level];
2771 mImageArray[level] = NULL;
2772 mLayerCounts[level] = 0;
2773 }
2774}
2775
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002776void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002777{
2778 // If there currently is a corresponding storage texture image, it has these parameters
2779 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2780 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002781 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002782 const GLenum storageFormat = getBaseLevelInternalFormat();
2783
2784 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2785 {
2786 delete mImageArray[level][layer];
2787 }
2788 delete[] mImageArray[level];
2789 mImageArray[level] = NULL;
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002790 mLayerCounts[level] = size.depth;
Brandon Jones142ec422014-07-16 10:31:30 -07002791
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002792 if (size.depth > 0)
Brandon Jones142ec422014-07-16 10:31:30 -07002793 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002794 mImageArray[level] = new ImageD3D*[size.depth]();
Brandon Jones142ec422014-07-16 10:31:30 -07002795
2796 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2797 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002798 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002799 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
2800 gl::Extents(size.width, size.height, 1), false);
Brandon Jones142ec422014-07-16 10:31:30 -07002801 }
2802 }
2803
2804 if (mTexStorage)
2805 {
2806 const int storageLevels = mTexStorage->getLevelCount();
2807
2808 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002809 size.width != storageWidth ||
2810 size.height != storageHeight ||
2811 size.depth != storageDepth ||
Brandon Jones142ec422014-07-16 10:31:30 -07002812 internalformat != storageFormat) // Discard mismatched storage
2813 {
2814 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2815 {
2816 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2817 {
2818 mImageArray[level][layer]->markDirty();
2819 }
2820 }
2821
2822 delete mTexStorage;
2823 mTexStorage = NULL;
2824 mDirtyImages = true;
2825 }
2826 }
2827}
2828
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002829gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2830{
2831 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2832}
2833
Jamie Madillcb83dc12014-09-29 10:46:12 -04002834gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2835{
2836 return gl::ImageIndex::Make2DArray(mip, layer);
2837}
2838
Jamie Madill710e5772014-10-20 17:13:53 -04002839bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2840{
2841 // Check for having a storage and the right type of index
2842 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2843 {
2844 return false;
2845 }
2846
2847 // Check the mip index
2848 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2849 {
2850 return false;
2851 }
2852
2853 // Check the layer index
2854 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2855}
2856
Brandon Jones78b1acd2014-07-15 15:33:07 -07002857}