blob: 19201407ad70a6bc8a6aec1cfffe113995ae65b4 [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"
19#include "libANGLE/renderer/RenderTarget.h"
20#include "libANGLE/renderer/d3d/BufferD3D.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050021#include "libANGLE/renderer/d3d/ImageD3D.h"
22#include "libANGLE/renderer/d3d/RendererD3D.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 Lang1ba6b8d2014-08-28 10:57:31 -0400293 GLenum sizedInternalFormat, GLenum type, RenderTarget *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
355 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400356 initMipmapsImages();
357
Austin Kinross215b37a2014-12-22 12:56:07 -0800358 if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
359 {
360 // Switch to using the mipmapped texture.
361 gl::Error error = getNativeTexture()->useLevelZeroWorkaroundTexture(false);
362 if (error.isError())
363 {
364 return error;
365 }
366 }
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 Lang64f23f62014-09-10 14:40:12 -0400623 RenderTarget *destRenderTarget = NULL;
624 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 Lang64f23f62014-09-10 14:40:12 -0400666 RenderTarget *renderTarget = NULL;
667 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
Jamie Madille76bdda2014-10-20 17:13:52 -0400731 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700732 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500733 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400734 if (error.isError())
735 {
736 return error;
737 }
738
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700739 mDirtyImages = true;
740 }
741 else
742 {
Geoff Langef7b0162014-09-04 13:29:23 -0400743 gl::Error error = ensureRenderTarget();
744 if (error.isError())
745 {
746 return error;
747 }
748
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700749 mImageArray[level]->markClean();
750
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500751 if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700752 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500753 gl::Error error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400754 if (error.isError())
755 {
756 return error;
757 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700758 }
759 }
Geoff Langef7b0162014-09-04 13:29:23 -0400760
761 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700762}
763
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500764gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
765 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700766{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500767 ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700768
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700769 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
770 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700771
Jamie Madille76bdda2014-10-20 17:13:52 -0400772 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400773
Jamie Madille76bdda2014-10-20 17:13:52 -0400774 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700775 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500776 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400777 if (error.isError())
778 {
779 return error;
780 }
781
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700782 mDirtyImages = true;
783 }
784 else
785 {
Geoff Langef7b0162014-09-04 13:29:23 -0400786 gl::Error error = ensureRenderTarget();
787 if (error.isError())
788 {
789 return error;
790 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700791
792 if (isValidLevel(level))
793 {
Geoff Langef7b0162014-09-04 13:29:23 -0400794 error = updateStorageLevel(level);
795 if (error.isError())
796 {
797 return error;
798 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700799
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500800 error = mRenderer->copyImage2D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -0400801 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500802 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400803 if (error.isError())
804 {
805 return error;
806 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700807 }
808 }
Geoff Langef7b0162014-09-04 13:29:23 -0400809
810 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700811}
812
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500813gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700814{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500815 ASSERT(GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700816
Geoff Lang8fed1f72015-01-09 11:09:33 -0500817 for (size_t level = 0; level < levels; level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500819 gl::Extents levelSize(std::max(1, size.width >> level),
820 std::max(1, size.height >> level),
821 1);
822 mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700823 }
824
825 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
826 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500827 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700828 }
829
Geoff Lang1f8532b2014-09-05 09:46:13 -0400830 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400831 bool renderTarget = IsRenderTargetUsage(mUsage);
Austin Kinross215b37a2014-12-22 12:56:07 -0800832 TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400833
834 gl::Error error = setCompleteTexStorage(storage);
835 if (error.isError())
836 {
837 SafeDelete(storage);
838 return error;
839 }
840
841 mImmutable = true;
842
843 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700844}
845
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700846void TextureD3D_2D::bindTexImage(egl::Surface *surface)
847{
848 GLenum internalformat = surface->getFormat();
849
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500850 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
851 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700852
853 if (mTexStorage)
854 {
855 SafeDelete(mTexStorage);
856 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400857
Jamie Madillfb0580a2014-11-27 14:03:52 -0500858 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
859 ASSERT(surfaceD3D);
860
861 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700862
863 mDirtyImages = true;
864}
865
866void TextureD3D_2D::releaseTexImage()
867{
868 if (mTexStorage)
869 {
870 SafeDelete(mTexStorage);
871 }
872
873 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
874 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500875 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700876 }
877}
878
Jamie Madill4aa79e12014-09-29 10:46:14 -0400879void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700880{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700881 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700883 for (int level = 1; level < levelCount; level++)
884 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500885 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
886 std::max(getBaseLevelHeight() >> level, 1),
887 1);
888
889 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700890 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700891}
892
Jamie Madillac7579c2014-09-17 16:59:33 -0400893unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700894{
Jamie Madillac7579c2014-09-17 16:59:33 -0400895 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400896 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700897}
898
Geoff Lang64f23f62014-09-10 14:40:12 -0400899gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700900{
Jamie Madillac7579c2014-09-17 16:59:33 -0400901 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700902
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700903 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400904 gl::Error error = ensureRenderTarget();
905 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700906 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400907 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700908 }
909
Geoff Langef7b0162014-09-04 13:29:23 -0400910 error = updateStorageLevel(index.mipIndex);
911 if (error.isError())
912 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400913 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400914 }
915
Geoff Lang64f23f62014-09-10 14:40:12 -0400916 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700917}
918
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919bool TextureD3D_2D::isValidLevel(int level) const
920{
921 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
922}
923
924bool TextureD3D_2D::isLevelComplete(int level) const
925{
926 if (isImmutable())
927 {
928 return true;
929 }
930
Geoff Langb4dedf32015-01-05 14:08:53 -0500931 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700932
933 GLsizei width = baseImage->getWidth();
934 GLsizei height = baseImage->getHeight();
935
936 if (width <= 0 || height <= 0)
937 {
938 return false;
939 }
940
941 // The base image level is complete if the width and height are positive
942 if (level == 0)
943 {
944 return true;
945 }
946
947 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700948 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700949
950 if (image->getInternalFormat() != baseImage->getInternalFormat())
951 {
952 return false;
953 }
954
955 if (image->getWidth() != std::max(1, width >> level))
956 {
957 return false;
958 }
959
960 if (image->getHeight() != std::max(1, height >> level))
961 {
962 return false;
963 }
964
965 return true;
966}
967
Jamie Madille76bdda2014-10-20 17:13:52 -0400968bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
969{
970 return isLevelComplete(index.mipIndex);
971}
972
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700973// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400974gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700975{
976 // Only initialize the first time this texture is used as a render target or shader resource
977 if (mTexStorage)
978 {
Geoff Langef7b0162014-09-04 13:29:23 -0400979 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700980 }
981
982 // do not attempt to create storage for nonexistant data
983 if (!isLevelComplete(0))
984 {
Geoff Langef7b0162014-09-04 13:29:23 -0400985 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700986 }
987
988 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
989
Geoff Langef7b0162014-09-04 13:29:23 -0400990 TextureStorage *storage = NULL;
991 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
992 if (error.isError())
993 {
994 return error;
995 }
996
997 error = setCompleteTexStorage(storage);
998 if (error.isError())
999 {
1000 SafeDelete(storage);
1001 return error;
1002 }
1003
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001004 ASSERT(mTexStorage);
1005
1006 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001007 error = updateStorage();
1008 if (error.isError())
1009 {
1010 return error;
1011 }
1012
1013 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001014}
1015
Geoff Langef7b0162014-09-04 13:29:23 -04001016gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001017{
1018 GLsizei width = getBaseLevelWidth();
1019 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001020 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001021
1022 ASSERT(width > 0 && height > 0);
1023
1024 // use existing storage level count, when previously specified by TexStorage*D
1025 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1026
Austin Kinross215b37a2014-12-22 12:56:07 -08001027 bool hintLevelZeroOnly = false;
1028 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1029 {
1030 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
1031 // Otherwise, it should use the level-zero-only texture.
1032 hintLevelZeroOnly = true;
1033 int level = 1;
1034 while (hintLevelZeroOnly && level < levels)
1035 {
1036 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1037 level += 1;
1038 }
1039 }
1040
Geoff Langef7b0162014-09-04 13:29:23 -04001041 // TODO(geofflang): Determine if the texture creation succeeded
Austin Kinross215b37a2014-12-22 12:56:07 -08001042 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly);
Geoff Langef7b0162014-09-04 13:29:23 -04001043
1044 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001045}
1046
Geoff Langef7b0162014-09-04 13:29:23 -04001047gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001048{
Geoff Langef7b0162014-09-04 13:29:23 -04001049 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001050 {
Geoff Langef7b0162014-09-04 13:29:23 -04001051 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001052 {
Geoff Langef7b0162014-09-04 13:29:23 -04001053 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1054 if (error.isError())
1055 {
1056 return error;
1057 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001058 }
1059 }
1060
Geoff Langef7b0162014-09-04 13:29:23 -04001061 SafeDelete(mTexStorage);
1062 mTexStorage = newCompleteTexStorage;
1063
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001064 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001065
1066 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001067}
1068
Geoff Langef7b0162014-09-04 13:29:23 -04001069gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001070{
1071 ASSERT(mTexStorage != NULL);
1072 GLint storageLevels = mTexStorage->getLevelCount();
1073 for (int level = 0; level < storageLevels; level++)
1074 {
1075 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1076 {
Geoff Langef7b0162014-09-04 13:29:23 -04001077 gl::Error error = updateStorageLevel(level);
1078 if (error.isError())
1079 {
1080 return error;
1081 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001082 }
1083 }
Geoff Langef7b0162014-09-04 13:29:23 -04001084
1085 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001086}
1087
Geoff Langef7b0162014-09-04 13:29:23 -04001088gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001089{
1090 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1091 ASSERT(isLevelComplete(level));
1092
1093 if (mImageArray[level]->isDirty())
1094 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001095 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1096 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001097 gl::Error error = commitRegion(index, region);
1098 if (error.isError())
1099 {
1100 return error;
1101 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001102 }
Geoff Langef7b0162014-09-04 13:29:23 -04001103
1104 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001105}
1106
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001107void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001108{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001109 ASSERT(size.depth == 1);
1110
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001111 // If there currently is a corresponding storage texture image, it has these parameters
1112 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1113 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1114 const GLenum storageFormat = getBaseLevelInternalFormat();
1115
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001116 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001117
1118 if (mTexStorage)
1119 {
1120 const int storageLevels = mTexStorage->getLevelCount();
1121
1122 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001123 size.width != storageWidth ||
1124 size.height != storageHeight ||
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001125 internalformat != storageFormat) // Discard mismatched storage
1126 {
1127 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1128 {
1129 mImageArray[i]->markDirty();
1130 }
1131
1132 SafeDelete(mTexStorage);
1133 mDirtyImages = true;
1134 }
1135 }
1136}
1137
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001138gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1139{
1140 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1141}
Brandon Jones0511e802014-07-14 16:27:26 -07001142
Jamie Madillcb83dc12014-09-29 10:46:12 -04001143gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1144{
1145 // "layer" does not apply to 2D Textures.
1146 return gl::ImageIndex::Make2D(mip);
1147}
1148
Jamie Madill710e5772014-10-20 17:13:53 -04001149bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1150{
1151 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1152 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1153}
1154
Jamie Madill93e13fb2014-11-06 15:27:25 -05001155TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001156 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001157{
1158 for (int i = 0; i < 6; i++)
1159 {
1160 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1161 {
Geoff Langb4dedf32015-01-05 14:08:53 -05001162 mImageArray[i][j] = renderer->createImage();
Brandon Jones0511e802014-07-14 16:27:26 -07001163 }
1164 }
1165}
1166
1167TextureD3D_Cube::~TextureD3D_Cube()
1168{
Austin Kinross69822602014-08-12 15:51:37 -07001169 // Delete the Images before the TextureStorage.
1170 // Images might be relying on the TextureStorage for some of their data.
1171 // 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 -07001172 for (int i = 0; i < 6; i++)
1173 {
1174 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1175 {
1176 SafeDelete(mImageArray[i][j]);
1177 }
1178 }
Austin Kinross69822602014-08-12 15:51:37 -07001179
1180 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001181}
1182
Geoff Langb4dedf32015-01-05 14:08:53 -05001183ImageD3D *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
1185 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001186 ASSERT(layer >= 0 && layer < 6);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001187 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001188}
1189
Geoff Langb4dedf32015-01-05 14:08:53 -05001190ImageD3D *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04001191{
1192 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001193 ASSERT(index.layerIndex >= 0 && index.layerIndex < 6);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001194 return mImageArray[index.layerIndex][index.mipIndex];
1195}
1196
Brandon Jonescef06ff2014-08-05 13:27:48 -07001197GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001198{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001199 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1200 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001201}
1202
Brandon Jonescef06ff2014-08-05 13:27:48 -07001203GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001204{
1205 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001206 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001207 else
1208 return GL_NONE;
1209}
1210
Brandon Jonescef06ff2014-08-05 13:27:48 -07001211bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001212{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001213 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001214}
1215
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001216gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1217 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001218{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001219 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001220
Geoff Lang5d601382014-07-22 15:14:06 -04001221 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001222 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001223
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001224 redefineImage(index.layerIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001225
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001226 return TextureD3D::setImage(index, type, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001227}
1228
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001229gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1230 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001231{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001232 ASSERT(area.depth == 1 && area.z == 0);
1233
1234 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
1235 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
1236}
1237
1238gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1239 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1240{
1241 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001242
Brandon Jones0511e802014-07-14 16:27:26 -07001243 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Geoff Lang691e58c2014-12-19 17:03:25 -05001244 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001245
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001246 redefineImage(faceIndex, level, internalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001247
Jamie Madillfeda4d22014-09-17 13:03:29 -04001248 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001249 return TextureD3D::setCompressedImage(index, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001250}
1251
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001252gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1253 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001254{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001255 ASSERT(area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001256
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001257 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001258
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001259 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001260 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001261 {
Geoff Langb5348332014-09-02 13:16:34 -04001262 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001263 }
Geoff Langb5348332014-09-02 13:16:34 -04001264
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001265 return commitRegion(index, area);
Brandon Jones0511e802014-07-14 16:27:26 -07001266}
1267
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001268gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1269 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001270{
Geoff Lang691e58c2014-12-19 17:03:25 -05001271 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001272 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04001273
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001274 gl::Extents size(sourceArea.width, sourceArea.height, 1);
1275 redefineImage(faceIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001276
Jamie Madille76bdda2014-10-20 17:13:52 -04001277 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001278 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001279
Jamie Madille76bdda2014-10-20 17:13:52 -04001280 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001281 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001282 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001283 if (error.isError())
1284 {
1285 return error;
1286 }
1287
Brandon Jones0511e802014-07-14 16:27:26 -07001288 mDirtyImages = true;
1289 }
1290 else
1291 {
Geoff Langef7b0162014-09-04 13:29:23 -04001292 gl::Error error = ensureRenderTarget();
1293 if (error.isError())
1294 {
1295 return error;
1296 }
1297
Brandon Jones0511e802014-07-14 16:27:26 -07001298 mImageArray[faceIndex][level]->markClean();
1299
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001300 ASSERT(size.width == size.height);
Brandon Jones0511e802014-07-14 16:27:26 -07001301
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001302 if (size.width > 0 && isValidFaceLevel(faceIndex, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001303 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001304 error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001305 if (error.isError())
1306 {
1307 return error;
1308 }
Brandon Jones0511e802014-07-14 16:27:26 -07001309 }
1310 }
Geoff Langef7b0162014-09-04 13:29:23 -04001311
1312 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001313}
1314
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001315gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1316 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001317{
Geoff Lang691e58c2014-12-19 17:03:25 -05001318 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001319
Jamie Madille76bdda2014-10-20 17:13:52 -04001320 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001321
Jamie Madille76bdda2014-10-20 17:13:52 -04001322 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001323 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001324 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001325 if (error.isError())
1326 {
1327 return error;
1328 }
1329
Brandon Jones0511e802014-07-14 16:27:26 -07001330 mDirtyImages = true;
1331 }
1332 else
1333 {
Geoff Langef7b0162014-09-04 13:29:23 -04001334 gl::Error error = ensureRenderTarget();
1335 if (error.isError())
1336 {
1337 return error;
1338 }
Brandon Jones0511e802014-07-14 16:27:26 -07001339
1340 if (isValidFaceLevel(faceIndex, level))
1341 {
Geoff Langef7b0162014-09-04 13:29:23 -04001342 error = updateStorageFaceLevel(faceIndex, level);
1343 if (error.isError())
1344 {
1345 return error;
1346 }
Brandon Jones0511e802014-07-14 16:27:26 -07001347
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001348 error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1349 destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001350 if (error.isError())
1351 {
1352 return error;
1353 }
Brandon Jones0511e802014-07-14 16:27:26 -07001354 }
1355 }
Geoff Langef7b0162014-09-04 13:29:23 -04001356
1357 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001358}
1359
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001360gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001361{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001362 ASSERT(size.width == size.height);
1363 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001364
Geoff Lang8fed1f72015-01-09 11:09:33 -05001365 for (size_t level = 0; level < levels; level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001366 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001367 GLsizei mipSize = std::max(1, size.width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001368 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1369 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001370 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001371 }
1372 }
1373
1374 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1375 {
1376 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1377 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001378 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001379 }
1380 }
1381
Geoff Lang1f8532b2014-09-05 09:46:13 -04001382 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001383 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001384 TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001385
1386 gl::Error error = setCompleteTexStorage(storage);
1387 if (error.isError())
1388 {
1389 SafeDelete(storage);
1390 return error;
1391 }
1392
1393 mImmutable = true;
1394
1395 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001396}
1397
Brandon Jones0511e802014-07-14 16:27:26 -07001398// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1399bool TextureD3D_Cube::isCubeComplete() const
1400{
1401 int baseWidth = getBaseLevelWidth();
1402 int baseHeight = getBaseLevelHeight();
1403 GLenum baseFormat = getBaseLevelInternalFormat();
1404
1405 if (baseWidth <= 0 || baseWidth != baseHeight)
1406 {
1407 return false;
1408 }
1409
1410 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1411 {
1412 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1413
1414 if (faceBaseImage.getWidth() != baseWidth ||
1415 faceBaseImage.getHeight() != baseHeight ||
1416 faceBaseImage.getInternalFormat() != baseFormat )
1417 {
1418 return false;
1419 }
1420 }
1421
1422 return true;
1423}
1424
Brandon Jones6053a522014-07-25 16:22:09 -07001425void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1426{
1427 UNREACHABLE();
1428}
1429
1430void TextureD3D_Cube::releaseTexImage()
1431{
1432 UNREACHABLE();
1433}
1434
1435
Jamie Madill4aa79e12014-09-29 10:46:14 -04001436void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001437{
1438 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1439 int levelCount = mipLevels();
1440 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1441 {
1442 for (int level = 1; level < levelCount; level++)
1443 {
1444 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001445 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1446 gl::Extents(faceLevelSize, faceLevelSize, 1));
Brandon Jones0511e802014-07-14 16:27:26 -07001447 }
1448 }
Brandon Jones0511e802014-07-14 16:27:26 -07001449}
1450
Jamie Madillac7579c2014-09-17 16:59:33 -04001451unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001452{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001453 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001454}
1455
Geoff Lang64f23f62014-09-10 14:40:12 -04001456gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001457{
Geoff Lang691e58c2014-12-19 17:03:25 -05001458 ASSERT(gl::IsCubeMapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001459
1460 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001461 gl::Error error = ensureRenderTarget();
1462 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001463 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001464 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001465 }
1466
Geoff Langef7b0162014-09-04 13:29:23 -04001467 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1468 if (error.isError())
1469 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001470 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001471 }
1472
Geoff Lang64f23f62014-09-10 14:40:12 -04001473 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001474}
1475
Geoff Langef7b0162014-09-04 13:29:23 -04001476gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001477{
1478 // Only initialize the first time this texture is used as a render target or shader resource
1479 if (mTexStorage)
1480 {
Geoff Langef7b0162014-09-04 13:29:23 -04001481 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001482 }
1483
1484 // do not attempt to create storage for nonexistant data
1485 if (!isFaceLevelComplete(0, 0))
1486 {
Geoff Langef7b0162014-09-04 13:29:23 -04001487 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001488 }
1489
1490 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1491
Geoff Langef7b0162014-09-04 13:29:23 -04001492 TextureStorage *storage = NULL;
1493 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1494 if (error.isError())
1495 {
1496 return error;
1497 }
1498
1499 error = setCompleteTexStorage(storage);
1500 if (error.isError())
1501 {
1502 SafeDelete(storage);
1503 return error;
1504 }
1505
Brandon Jones0511e802014-07-14 16:27:26 -07001506 ASSERT(mTexStorage);
1507
1508 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001509 error = updateStorage();
1510 if (error.isError())
1511 {
1512 return error;
1513 }
1514
1515 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001516}
1517
Geoff Langef7b0162014-09-04 13:29:23 -04001518gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001519{
1520 GLsizei size = getBaseLevelWidth();
1521
1522 ASSERT(size > 0);
1523
1524 // use existing storage level count, when previously specified by TexStorage*D
1525 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1526
Geoff Langef7b0162014-09-04 13:29:23 -04001527 // TODO (geofflang): detect if storage creation succeeded
1528 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1529
1530 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001531}
1532
Geoff Langef7b0162014-09-04 13:29:23 -04001533gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001534{
Geoff Langef7b0162014-09-04 13:29:23 -04001535 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001536 {
1537 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1538 {
Geoff Langef7b0162014-09-04 13:29:23 -04001539 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001540 {
Geoff Langef7b0162014-09-04 13:29:23 -04001541 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1542 if (error.isError())
1543 {
1544 return error;
1545 }
Brandon Jones0511e802014-07-14 16:27:26 -07001546 }
1547 }
1548 }
1549
Geoff Langef7b0162014-09-04 13:29:23 -04001550 SafeDelete(mTexStorage);
1551 mTexStorage = newCompleteTexStorage;
1552
Brandon Jones0511e802014-07-14 16:27:26 -07001553 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001554 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001555}
1556
Geoff Langef7b0162014-09-04 13:29:23 -04001557gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001558{
1559 ASSERT(mTexStorage != NULL);
1560 GLint storageLevels = mTexStorage->getLevelCount();
1561 for (int face = 0; face < 6; face++)
1562 {
1563 for (int level = 0; level < storageLevels; level++)
1564 {
1565 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1566 {
Geoff Langef7b0162014-09-04 13:29:23 -04001567 gl::Error error = updateStorageFaceLevel(face, level);
1568 if (error.isError())
1569 {
1570 return error;
1571 }
Brandon Jones0511e802014-07-14 16:27:26 -07001572 }
1573 }
1574 }
Geoff Langef7b0162014-09-04 13:29:23 -04001575
1576 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001577}
1578
Brandon Jones0511e802014-07-14 16:27:26 -07001579bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1580{
1581 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1582}
1583
Brandon Jones0511e802014-07-14 16:27:26 -07001584bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1585{
1586 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1587
1588 if (isImmutable())
1589 {
1590 return true;
1591 }
1592
1593 int baseSize = getBaseLevelWidth();
1594
1595 if (baseSize <= 0)
1596 {
1597 return false;
1598 }
1599
1600 // "isCubeComplete" checks for base level completeness and we must call that
1601 // to determine if any face at level 0 is complete. We omit that check here
1602 // to avoid re-checking cube-completeness for every face at level 0.
1603 if (level == 0)
1604 {
1605 return true;
1606 }
1607
1608 // Check that non-zero levels are consistent with the base level.
1609 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1610
1611 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1612 {
1613 return false;
1614 }
1615
1616 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1617 {
1618 return false;
1619 }
1620
1621 return true;
1622}
1623
Jamie Madille76bdda2014-10-20 17:13:52 -04001624bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1625{
1626 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1627}
1628
Geoff Langef7b0162014-09-04 13:29:23 -04001629gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001630{
1631 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1632 ImageD3D *image = mImageArray[faceIndex][level];
1633
1634 if (image->isDirty())
1635 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001636 GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001637 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1638 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001639 gl::Error error = commitRegion(index, region);
1640 if (error.isError())
1641 {
1642 return error;
1643 }
Brandon Jones0511e802014-07-14 16:27:26 -07001644 }
Geoff Langef7b0162014-09-04 13:29:23 -04001645
1646 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001647}
1648
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001649void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001650{
1651 // If there currently is a corresponding storage texture image, it has these parameters
1652 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1653 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1654 const GLenum storageFormat = getBaseLevelInternalFormat();
1655
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001656 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001657
1658 if (mTexStorage)
1659 {
1660 const int storageLevels = mTexStorage->getLevelCount();
1661
1662 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001663 size.width != storageWidth ||
1664 size.height != storageHeight ||
Brandon Jones0511e802014-07-14 16:27:26 -07001665 internalformat != storageFormat) // Discard mismatched storage
1666 {
1667 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1668 {
1669 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1670 {
1671 mImageArray[faceIndex][level]->markDirty();
1672 }
1673 }
1674
1675 SafeDelete(mTexStorage);
1676
1677 mDirtyImages = true;
1678 }
1679 }
1680}
1681
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001682gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1683{
1684 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1685}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001686
Jamie Madillcb83dc12014-09-29 10:46:12 -04001687gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1688{
1689 // The "layer" of the image index corresponds to the cube face
Geoff Lang691e58c2014-12-19 17:03:25 -05001690 return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip);
Jamie Madillcb83dc12014-09-29 10:46:12 -04001691}
1692
Jamie Madill710e5772014-10-20 17:13:53 -04001693bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1694{
Geoff Lang691e58c2014-12-19 17:03:25 -05001695 return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) &&
Jamie Madill710e5772014-10-20 17:13:53 -04001696 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1697}
1698
Jamie Madill93e13fb2014-11-06 15:27:25 -05001699TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001700 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001701{
1702 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1703 {
Geoff Langb4dedf32015-01-05 14:08:53 -05001704 mImageArray[i] = renderer->createImage();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001705 }
1706}
1707
1708TextureD3D_3D::~TextureD3D_3D()
1709{
Austin Kinross69822602014-08-12 15:51:37 -07001710 // Delete the Images before the TextureStorage.
1711 // Images might be relying on the TextureStorage for some of their data.
1712 // 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 -07001713 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1714 {
1715 delete mImageArray[i];
1716 }
Austin Kinross69822602014-08-12 15:51:37 -07001717
1718 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001719}
1720
Geoff Langb4dedf32015-01-05 14:08:53 -05001721ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001722{
1723 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001724 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001725 return mImageArray[level];
1726}
1727
Geoff Langb4dedf32015-01-05 14:08:53 -05001728ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04001729{
1730 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001731 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001732 ASSERT(index.type == GL_TEXTURE_3D);
1733 return mImageArray[index.mipIndex];
1734}
1735
Brandon Jonescef06ff2014-08-05 13:27:48 -07001736GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001738 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1739 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001740}
1741
Brandon Jones78b1acd2014-07-15 15:33:07 -07001742GLsizei TextureD3D_3D::getWidth(GLint level) const
1743{
1744 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1745 return mImageArray[level]->getWidth();
1746 else
1747 return 0;
1748}
1749
1750GLsizei TextureD3D_3D::getHeight(GLint level) const
1751{
1752 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1753 return mImageArray[level]->getHeight();
1754 else
1755 return 0;
1756}
1757
1758GLsizei TextureD3D_3D::getDepth(GLint level) const
1759{
1760 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1761 return mImageArray[level]->getDepth();
1762 else
1763 return 0;
1764}
1765
1766GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1767{
1768 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1769 return mImageArray[level]->getInternalFormat();
1770 else
1771 return GL_NONE;
1772}
1773
1774bool TextureD3D_3D::isDepth(GLint level) const
1775{
Geoff Lang5d601382014-07-22 15:14:06 -04001776 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777}
1778
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001779gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1780 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001781{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001782 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001783 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1784
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001785 redefineImage(level, sizedInternalFormat, size);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001786
1787 bool fastUnpacked = false;
1788
Jamie Madillba6bc952014-10-06 10:56:22 -04001789 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1790
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791 // 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 -05001792 if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001793 {
1794 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001795 RenderTarget *destRenderTarget = NULL;
1796 gl::Error error = getRenderTarget(index, &destRenderTarget);
1797 if (error.isError())
1798 {
1799 return error;
1800 }
1801
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1803
Geoff Lang64f23f62014-09-10 14:40:12 -04001804 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1805 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001807 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001808 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001809
1810 // Ensure we don't overwrite our newly initialized data
1811 mImageArray[level]->markClean();
1812
1813 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001814 }
1815
1816 if (!fastUnpacked)
1817 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001818 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001819 if (error.isError())
1820 {
1821 return error;
1822 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001823 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001824
1825 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001826}
1827
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001828gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1829 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001831 ASSERT(target == GL_TEXTURE_3D);
1832
Brandon Jones78b1acd2014-07-15 15:33:07 -07001833 bool fastUnpacked = false;
1834
Jamie Madillac7579c2014-09-17 16:59:33 -04001835 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1836
Brandon Jones78b1acd2014-07-15 15:33:07 -07001837 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1838 if (isFastUnpackable(unpack, getInternalFormat(level)))
1839 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001840 RenderTarget *destRenderTarget = NULL;
1841 gl::Error error = getRenderTarget(index, &destRenderTarget);
1842 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001843 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001844 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001845 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001846
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001847 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -04001848 if (error.isError())
1849 {
1850 return error;
1851 }
1852
1853 // Ensure we don't overwrite our newly initialized data
1854 mImageArray[level]->markClean();
1855
1856 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001857 }
1858
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001859 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001860 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001861 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001862 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001863
1864 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001865}
1866
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001867gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1868 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001869{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001870 ASSERT(target == GL_TEXTURE_3D);
1871
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001872 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1873 redefineImage(level, internalFormat, size);
1874
1875 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1876 return TextureD3D::setCompressedImage(index, unpack, pixels);
1877}
1878
1879gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1880 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1881{
1882 ASSERT(target == GL_TEXTURE_3D);
1883
1884 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1885 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001886 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001887 {
Geoff Langb5348332014-09-02 13:16:34 -04001888 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001889 }
Geoff Langb5348332014-09-02 13:16:34 -04001890
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001891 return commitRegion(index, area);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001892}
1893
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001894gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1895 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001896{
1897 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001898 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001899}
1900
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001901gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1902 const gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001903{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001904 ASSERT(target == GL_TEXTURE_3D);
1905
Jamie Madille76bdda2014-10-20 17:13:52 -04001906 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001907
Jamie Madille76bdda2014-10-20 17:13:52 -04001908 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001910 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001911 if (error.isError())
1912 {
1913 return error;
1914 }
1915
Brandon Jones78b1acd2014-07-15 15:33:07 -07001916 mDirtyImages = true;
1917 }
1918 else
1919 {
Geoff Langef7b0162014-09-04 13:29:23 -04001920 gl::Error error = ensureRenderTarget();
1921 if (error.isError())
1922 {
1923 return error;
1924 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001925
1926 if (isValidLevel(level))
1927 {
Geoff Langef7b0162014-09-04 13:29:23 -04001928 error = updateStorageLevel(level);
1929 if (error.isError())
1930 {
1931 return error;
1932 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001933
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001934 error = mRenderer->copyImage3D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -04001935 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001936 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001937 if (error.isError())
1938 {
1939 return error;
1940 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001941 }
1942 }
Geoff Langef7b0162014-09-04 13:29:23 -04001943
1944 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001945}
1946
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001947gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001948{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001949 ASSERT(target == GL_TEXTURE_3D);
1950
Geoff Lang8fed1f72015-01-09 11:09:33 -05001951 for (size_t level = 0; level < levels; level++)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001952 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001953 gl::Extents levelSize(std::max(1, size.width >> level),
1954 std::max(1, size.height >> level),
1955 std::max(1, size.depth >> level));
1956 mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001957 }
1958
1959 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1960 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001961 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001962 }
1963
Geoff Lang1f8532b2014-09-05 09:46:13 -04001964 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001965 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001966 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001967
1968 gl::Error error = setCompleteTexStorage(storage);
1969 if (error.isError())
1970 {
1971 SafeDelete(storage);
1972 return error;
1973 }
1974
1975 mImmutable = true;
1976
1977 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001978}
1979
Brandon Jones6053a522014-07-25 16:22:09 -07001980void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001981{
Brandon Jones6053a522014-07-25 16:22:09 -07001982 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001983}
1984
Brandon Jones6053a522014-07-25 16:22:09 -07001985void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001986{
Brandon Jones6053a522014-07-25 16:22:09 -07001987 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001988}
1989
Brandon Jones6053a522014-07-25 16:22:09 -07001990
Jamie Madill4aa79e12014-09-29 10:46:14 -04001991void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001992{
1993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1994 int levelCount = mipLevels();
1995 for (int level = 1; level < levelCount; level++)
1996 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001997 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
1998 std::max(getBaseLevelHeight() >> level, 1),
1999 std::max(getBaseLevelDepth() >> level, 1));
2000 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002001 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002}
2003
Jamie Madillac7579c2014-09-17 16:59:33 -04002004unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002005{
Geoff Langef7b0162014-09-04 13:29:23 -04002006 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002007}
2008
Geoff Lang64f23f62014-09-10 14:40:12 -04002009gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002010{
2011 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002012 gl::Error error = ensureRenderTarget();
2013 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002014 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002015 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002016 }
2017
Jamie Madillac7579c2014-09-17 16:59:33 -04002018 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002019 {
Geoff Langef7b0162014-09-04 13:29:23 -04002020 error = updateStorage();
2021 if (error.isError())
2022 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002023 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002024 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002025 }
2026 else
2027 {
Geoff Langef7b0162014-09-04 13:29:23 -04002028 error = updateStorageLevel(index.mipIndex);
2029 if (error.isError())
2030 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002031 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002032 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002033 }
2034
Geoff Lang64f23f62014-09-10 14:40:12 -04002035 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002036}
2037
Geoff Langef7b0162014-09-04 13:29:23 -04002038gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002039{
2040 // Only initialize the first time this texture is used as a render target or shader resource
2041 if (mTexStorage)
2042 {
Geoff Langef7b0162014-09-04 13:29:23 -04002043 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002044 }
2045
2046 // do not attempt to create storage for nonexistant data
2047 if (!isLevelComplete(0))
2048 {
Geoff Langef7b0162014-09-04 13:29:23 -04002049 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002050 }
2051
2052 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2053
Jamie Madill30d6c252014-11-13 10:03:33 -05002054 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002055 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2056 if (error.isError())
2057 {
2058 return error;
2059 }
2060
2061 error = setCompleteTexStorage(storage);
2062 if (error.isError())
2063 {
2064 SafeDelete(storage);
2065 return error;
2066 }
2067
Brandon Jones78b1acd2014-07-15 15:33:07 -07002068 ASSERT(mTexStorage);
2069
2070 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002071 error = updateStorage();
2072 if (error.isError())
2073 {
2074 return error;
2075 }
2076
2077 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002078}
2079
Geoff Langef7b0162014-09-04 13:29:23 -04002080gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002081{
2082 GLsizei width = getBaseLevelWidth();
2083 GLsizei height = getBaseLevelHeight();
2084 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002085 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002086
2087 ASSERT(width > 0 && height > 0 && depth > 0);
2088
2089 // use existing storage level count, when previously specified by TexStorage*D
2090 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2091
Geoff Langef7b0162014-09-04 13:29:23 -04002092 // TODO: Verify creation of the storage succeeded
2093 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
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::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099{
2100 SafeDelete(mTexStorage);
2101 mTexStorage = newCompleteTexStorage;
2102 mDirtyImages = true;
2103
2104 // We do not support managed 3D storage, as that is D3D9/ES2-only
2105 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002106
2107 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002108}
2109
Geoff Langef7b0162014-09-04 13:29:23 -04002110gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002111{
2112 ASSERT(mTexStorage != NULL);
2113 GLint storageLevels = mTexStorage->getLevelCount();
2114 for (int level = 0; level < storageLevels; level++)
2115 {
2116 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2117 {
Geoff Langef7b0162014-09-04 13:29:23 -04002118 gl::Error error = updateStorageLevel(level);
2119 if (error.isError())
2120 {
2121 return error;
2122 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002123 }
2124 }
Geoff Langef7b0162014-09-04 13:29:23 -04002125
2126 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002127}
2128
Brandon Jones78b1acd2014-07-15 15:33:07 -07002129bool TextureD3D_3D::isValidLevel(int level) const
2130{
2131 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2132}
2133
2134bool TextureD3D_3D::isLevelComplete(int level) const
2135{
2136 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2137
2138 if (isImmutable())
2139 {
2140 return true;
2141 }
2142
2143 GLsizei width = getBaseLevelWidth();
2144 GLsizei height = getBaseLevelHeight();
2145 GLsizei depth = getBaseLevelDepth();
2146
2147 if (width <= 0 || height <= 0 || depth <= 0)
2148 {
2149 return false;
2150 }
2151
2152 if (level == 0)
2153 {
2154 return true;
2155 }
2156
2157 ImageD3D *levelImage = mImageArray[level];
2158
2159 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2160 {
2161 return false;
2162 }
2163
2164 if (levelImage->getWidth() != std::max(1, width >> level))
2165 {
2166 return false;
2167 }
2168
2169 if (levelImage->getHeight() != std::max(1, height >> level))
2170 {
2171 return false;
2172 }
2173
2174 if (levelImage->getDepth() != std::max(1, depth >> level))
2175 {
2176 return false;
2177 }
2178
2179 return true;
2180}
2181
Jamie Madille76bdda2014-10-20 17:13:52 -04002182bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2183{
2184 return isLevelComplete(index.mipIndex);
2185}
2186
Geoff Langef7b0162014-09-04 13:29:23 -04002187gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002188{
2189 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2190 ASSERT(isLevelComplete(level));
2191
2192 if (mImageArray[level]->isDirty())
2193 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002194 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2195 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002196 gl::Error error = commitRegion(index, region);
2197 if (error.isError())
2198 {
2199 return error;
2200 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002201 }
Geoff Langef7b0162014-09-04 13:29:23 -04002202
2203 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002204}
2205
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002206void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002207{
2208 // If there currently is a corresponding storage texture image, it has these parameters
2209 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2210 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2211 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2212 const GLenum storageFormat = getBaseLevelInternalFormat();
2213
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002214 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002215
2216 if (mTexStorage)
2217 {
2218 const int storageLevels = mTexStorage->getLevelCount();
2219
2220 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002221 size.width != storageWidth ||
2222 size.height != storageHeight ||
2223 size.depth != storageDepth ||
Brandon Jones78b1acd2014-07-15 15:33:07 -07002224 internalformat != storageFormat) // Discard mismatched storage
2225 {
2226 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2227 {
2228 mImageArray[i]->markDirty();
2229 }
2230
2231 SafeDelete(mTexStorage);
2232 mDirtyImages = true;
2233 }
2234 }
2235}
2236
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002237gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2238{
2239 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2240 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2241}
Brandon Jones142ec422014-07-16 10:31:30 -07002242
Jamie Madillcb83dc12014-09-29 10:46:12 -04002243gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2244{
2245 // The "layer" here does not apply to 3D images. We use one Image per mip.
2246 return gl::ImageIndex::Make3D(mip);
2247}
2248
Jamie Madill710e5772014-10-20 17:13:53 -04002249bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2250{
2251 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2252 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2253}
2254
Jamie Madill93e13fb2014-11-06 15:27:25 -05002255TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002256 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002257{
2258 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2259 {
2260 mLayerCounts[level] = 0;
2261 mImageArray[level] = NULL;
2262 }
2263}
2264
2265TextureD3D_2DArray::~TextureD3D_2DArray()
2266{
Austin Kinross69822602014-08-12 15:51:37 -07002267 // Delete the Images before the TextureStorage.
2268 // Images might be relying on the TextureStorage for some of their data.
2269 // 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 -07002270 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002271 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002272}
2273
Geoff Langb4dedf32015-01-05 14:08:53 -05002274ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
Brandon Jones142ec422014-07-16 10:31:30 -07002275{
2276 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002277 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2278 layer < mLayerCounts[level]);
2279 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002280}
2281
Geoff Langb4dedf32015-01-05 14:08:53 -05002282ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04002283{
2284 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002285 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2286 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002287 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002288 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002289}
2290
Brandon Jones142ec422014-07-16 10:31:30 -07002291GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2292{
2293 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2294 return mLayerCounts[level];
2295}
2296
Brandon Jones142ec422014-07-16 10:31:30 -07002297GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2298{
2299 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2300}
2301
2302GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2303{
2304 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2305}
2306
Brandon Jones142ec422014-07-16 10:31:30 -07002307GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2308{
2309 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2310}
2311
2312bool TextureD3D_2DArray::isDepth(GLint level) const
2313{
Geoff Lang5d601382014-07-22 15:14:06 -04002314 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002315}
2316
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002317gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
2318 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002319{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002320 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2321
Geoff Lang5d601382014-07-22 15:14:06 -04002322 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2323
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002324 redefineImage(level, sizedInternalFormat, size);
Brandon Jones142ec422014-07-16 10:31:30 -07002325
Geoff Lang5d601382014-07-22 15:14:06 -04002326 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002327 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002328
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002329 for (int i = 0; i < size.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002330 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002331 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002332 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002333 gl::Error error = TextureD3D::setImage(index, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002334 if (error.isError())
2335 {
2336 return error;
2337 }
Brandon Jones142ec422014-07-16 10:31:30 -07002338 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002339
2340 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002341}
2342
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002343gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
2344 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002345{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002346 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2347
Geoff Lang5d601382014-07-22 15:14:06 -04002348 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002349 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002350
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002351 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002352 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002353 int layer = area.z + i;
2354 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2355
2356 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002357
Jamie Madillfeda4d22014-09-17 13:03:29 -04002358 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002359 gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002360 if (error.isError())
2361 {
2362 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002363 }
2364 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002365
2366 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002367}
2368
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002369gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
2370 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
2371{
2372 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2373
2374 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2375 redefineImage(level, internalFormat, size);
2376
2377 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2378 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1);
2379
2380 for (int i = 0; i < size.depth; i++)
2381 {
2382 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2383
2384 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2385 gl::Error error = TextureD3D::setCompressedImage(index, unpack, layerPixels);
2386 if (error.isError())
2387 {
2388 return error;
2389 }
2390 }
2391
2392 return gl::Error(GL_NO_ERROR);
2393}
2394
2395gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
2396 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002397{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002398 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2399
Geoff Lang5d601382014-07-22 15:14:06 -04002400 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002401 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002402
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002403 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002404 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002405 int layer = area.z + i;
2406 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Brandon Jones142ec422014-07-16 10:31:30 -07002407
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002408 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
2409
2410 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2411 gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, layerPixels);
Geoff Langb5348332014-09-02 13:16:34 -04002412 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002413 {
Geoff Langb5348332014-09-02 13:16:34 -04002414 return error;
2415 }
2416
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002417 error = commitRegion(index, layerArea);
Geoff Langb5348332014-09-02 13:16:34 -04002418 if (error.isError())
2419 {
2420 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002421 }
2422 }
Geoff Langb5348332014-09-02 13:16:34 -04002423
2424 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002425}
2426
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002427gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
2428 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002429{
2430 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002431 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002432}
2433
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002434gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
2435 const gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002436{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002437 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2438
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002439 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002440
Jamie Madille76bdda2014-10-20 17:13:52 -04002441 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002442 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002443 gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
2444 gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04002445 if (error.isError())
2446 {
2447 return error;
2448 }
2449
Brandon Jones142ec422014-07-16 10:31:30 -07002450 mDirtyImages = true;
2451 }
2452 else
2453 {
Geoff Langef7b0162014-09-04 13:29:23 -04002454 gl::Error error = ensureRenderTarget();
2455 if (error.isError())
2456 {
2457 return error;
2458 }
Brandon Jones142ec422014-07-16 10:31:30 -07002459
2460 if (isValidLevel(level))
2461 {
Geoff Langef7b0162014-09-04 13:29:23 -04002462 error = updateStorageLevel(level);
2463 if (error.isError())
2464 {
2465 return error;
2466 }
Brandon Jones142ec422014-07-16 10:31:30 -07002467
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002468 error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2469 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04002470 if (error.isError())
2471 {
2472 return error;
2473 }
Brandon Jones142ec422014-07-16 10:31:30 -07002474 }
2475 }
Geoff Langef7b0162014-09-04 13:29:23 -04002476 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002477}
2478
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002479gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002480{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002481 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2482
Brandon Jones142ec422014-07-16 10:31:30 -07002483 deleteImages();
2484
Geoff Lang8fed1f72015-01-09 11:09:33 -05002485 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
Brandon Jones142ec422014-07-16 10:31:30 -07002486 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002487 gl::Extents levelLayerSize(std::max(1, size.width >> level),
2488 std::max(1, size.height >> level),
2489 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002490
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002491 mLayerCounts[level] = (level < levels ? size.depth : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002492
2493 if (mLayerCounts[level] > 0)
2494 {
2495 // Create new images for this level
2496 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2497
2498 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2499 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002500 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002501 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true);
Brandon Jones142ec422014-07-16 10:31:30 -07002502 }
2503 }
2504 }
2505
Geoff Lang1f8532b2014-09-05 09:46:13 -04002506 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002507 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002508 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002509
2510 gl::Error error = setCompleteTexStorage(storage);
2511 if (error.isError())
2512 {
2513 SafeDelete(storage);
2514 return error;
2515 }
2516
2517 mImmutable = true;
2518
2519 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002520}
2521
Brandon Jones6053a522014-07-25 16:22:09 -07002522void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002523{
Brandon Jones6053a522014-07-25 16:22:09 -07002524 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002525}
2526
Brandon Jones6053a522014-07-25 16:22:09 -07002527void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002528{
Brandon Jones6053a522014-07-25 16:22:09 -07002529 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002530}
2531
Brandon Jones6053a522014-07-25 16:22:09 -07002532
Jamie Madill4aa79e12014-09-29 10:46:14 -04002533void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002534{
2535 int baseWidth = getBaseLevelWidth();
2536 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002537 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002538 GLenum baseFormat = getBaseLevelInternalFormat();
2539
2540 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2541 int levelCount = mipLevels();
2542 for (int level = 1; level < levelCount; level++)
2543 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002544 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
2545 std::max(baseHeight >> level, 1),
2546 baseDepth);
2547 redefineImage(level, baseFormat, levelLayerSize);
Brandon Jones142ec422014-07-16 10:31:30 -07002548 }
Brandon Jones142ec422014-07-16 10:31:30 -07002549}
2550
Jamie Madillac7579c2014-09-17 16:59:33 -04002551unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002552{
Geoff Langef7b0162014-09-04 13:29:23 -04002553 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002554}
2555
Geoff Lang64f23f62014-09-10 14:40:12 -04002556gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002557{
2558 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002559 gl::Error error = ensureRenderTarget();
2560 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002561 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002562 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002563 }
2564
Geoff Langef7b0162014-09-04 13:29:23 -04002565 error = updateStorageLevel(index.mipIndex);
2566 if (error.isError())
2567 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002568 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002569 }
2570
Geoff Lang64f23f62014-09-10 14:40:12 -04002571 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002572}
2573
Geoff Langef7b0162014-09-04 13:29:23 -04002574gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002575{
2576 // Only initialize the first time this texture is used as a render target or shader resource
2577 if (mTexStorage)
2578 {
Geoff Langef7b0162014-09-04 13:29:23 -04002579 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002580 }
2581
2582 // do not attempt to create storage for nonexistant data
2583 if (!isLevelComplete(0))
2584 {
Geoff Langef7b0162014-09-04 13:29:23 -04002585 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002586 }
2587
2588 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2589
Geoff Langef7b0162014-09-04 13:29:23 -04002590 TextureStorage *storage = NULL;
2591 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2592 if (error.isError())
2593 {
2594 return error;
2595 }
2596
2597 error = setCompleteTexStorage(storage);
2598 if (error.isError())
2599 {
2600 SafeDelete(storage);
2601 return error;
2602 }
2603
Brandon Jones142ec422014-07-16 10:31:30 -07002604 ASSERT(mTexStorage);
2605
2606 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002607 error = updateStorage();
2608 if (error.isError())
2609 {
2610 return error;
2611 }
2612
2613 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002614}
2615
Geoff Langef7b0162014-09-04 13:29:23 -04002616gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002617{
2618 GLsizei width = getBaseLevelWidth();
2619 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002620 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002621 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002622
2623 ASSERT(width > 0 && height > 0 && depth > 0);
2624
2625 // use existing storage level count, when previously specified by TexStorage*D
2626 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2627
Geoff Langef7b0162014-09-04 13:29:23 -04002628 // TODO(geofflang): Verify storage creation succeeds
2629 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
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::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002635{
2636 SafeDelete(mTexStorage);
2637 mTexStorage = newCompleteTexStorage;
2638 mDirtyImages = true;
2639
2640 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2641 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002642
2643 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002644}
2645
Geoff Langef7b0162014-09-04 13:29:23 -04002646gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002647{
2648 ASSERT(mTexStorage != NULL);
2649 GLint storageLevels = mTexStorage->getLevelCount();
2650 for (int level = 0; level < storageLevels; level++)
2651 {
2652 if (isLevelComplete(level))
2653 {
Geoff Langef7b0162014-09-04 13:29:23 -04002654 gl::Error error = updateStorageLevel(level);
2655 if (error.isError())
2656 {
2657 return error;
2658 }
Brandon Jones142ec422014-07-16 10:31:30 -07002659 }
2660 }
Geoff Langef7b0162014-09-04 13:29:23 -04002661
2662 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002663}
2664
Brandon Jones142ec422014-07-16 10:31:30 -07002665bool TextureD3D_2DArray::isValidLevel(int level) const
2666{
2667 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2668}
2669
2670bool TextureD3D_2DArray::isLevelComplete(int level) const
2671{
2672 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2673
2674 if (isImmutable())
2675 {
2676 return true;
2677 }
2678
2679 GLsizei width = getBaseLevelWidth();
2680 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002681 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002682
2683 if (width <= 0 || height <= 0 || layers <= 0)
2684 {
2685 return false;
2686 }
2687
2688 if (level == 0)
2689 {
2690 return true;
2691 }
2692
2693 if (getInternalFormat(level) != getInternalFormat(0))
2694 {
2695 return false;
2696 }
2697
2698 if (getWidth(level) != std::max(1, width >> level))
2699 {
2700 return false;
2701 }
2702
2703 if (getHeight(level) != std::max(1, height >> level))
2704 {
2705 return false;
2706 }
2707
Jamie Madill3269bcb2014-09-30 16:33:52 -04002708 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002709 {
2710 return false;
2711 }
2712
2713 return true;
2714}
2715
Jamie Madille76bdda2014-10-20 17:13:52 -04002716bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2717{
2718 return isLevelComplete(index.mipIndex);
2719}
2720
Geoff Langef7b0162014-09-04 13:29:23 -04002721gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002722{
2723 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2724 ASSERT(isLevelComplete(level));
2725
2726 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2727 {
2728 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2729 if (mImageArray[level][layer]->isDirty())
2730 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002731 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2732 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002733 gl::Error error = commitRegion(index, region);
2734 if (error.isError())
2735 {
2736 return error;
2737 }
Brandon Jones142ec422014-07-16 10:31:30 -07002738 }
2739 }
Geoff Langef7b0162014-09-04 13:29:23 -04002740
2741 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002742}
2743
2744void TextureD3D_2DArray::deleteImages()
2745{
2746 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2747 {
2748 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2749 {
2750 delete mImageArray[level][layer];
2751 }
2752 delete[] mImageArray[level];
2753 mImageArray[level] = NULL;
2754 mLayerCounts[level] = 0;
2755 }
2756}
2757
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002758void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002759{
2760 // If there currently is a corresponding storage texture image, it has these parameters
2761 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2762 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002763 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002764 const GLenum storageFormat = getBaseLevelInternalFormat();
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;
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002772 mLayerCounts[level] = size.depth;
Brandon Jones142ec422014-07-16 10:31:30 -07002773
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002774 if (size.depth > 0)
Brandon Jones142ec422014-07-16 10:31:30 -07002775 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002776 mImageArray[level] = new ImageD3D*[size.depth]();
Brandon Jones142ec422014-07-16 10:31:30 -07002777
2778 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2779 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002780 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002781 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
2782 gl::Extents(size.width, size.height, 1), false);
Brandon Jones142ec422014-07-16 10:31:30 -07002783 }
2784 }
2785
2786 if (mTexStorage)
2787 {
2788 const int storageLevels = mTexStorage->getLevelCount();
2789
2790 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002791 size.width != storageWidth ||
2792 size.height != storageHeight ||
2793 size.depth != storageDepth ||
Brandon Jones142ec422014-07-16 10:31:30 -07002794 internalformat != storageFormat) // Discard mismatched storage
2795 {
2796 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2797 {
2798 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2799 {
2800 mImageArray[level][layer]->markDirty();
2801 }
2802 }
2803
2804 delete mTexStorage;
2805 mTexStorage = NULL;
2806 mDirtyImages = true;
2807 }
2808 }
2809}
2810
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002811gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2812{
2813 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2814}
2815
Jamie Madillcb83dc12014-09-29 10:46:12 -04002816gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2817{
2818 return gl::ImageIndex::Make2DArray(mip, layer);
2819}
2820
Jamie Madill710e5772014-10-20 17:13:53 -04002821bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2822{
2823 // Check for having a storage and the right type of index
2824 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2825 {
2826 return false;
2827 }
2828
2829 // Check the mip index
2830 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2831 {
2832 return false;
2833 }
2834
2835 // Check the layer index
2836 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2837}
2838
Brandon Jones78b1acd2014-07-15 15:33:07 -07002839}