blob: a808344e88deca022ac4fa10cadbf4b0e6101045 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Jamie Madillfb0580a2014-11-27 14:03:52 -05009#include "libANGLE/renderer/d3d/TextureD3D.h"
10
11#include "common/mathutil.h"
12#include "common/utilities.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Buffer.h"
14#include "libANGLE/Framebuffer.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050015#include "libANGLE/Surface.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Texture.h"
17#include "libANGLE/formatutils.h"
18#include "libANGLE/renderer/BufferImpl.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050019#include "libANGLE/renderer/d3d/BufferD3D.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050020#include "libANGLE/renderer/d3d/ImageD3D.h"
21#include "libANGLE/renderer/d3d/RendererD3D.h"
Geoff Langc2e75af2015-01-05 14:26:24 -050022#include "libANGLE/renderer/d3d/RenderTargetD3D.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050023#include "libANGLE/renderer/d3d/SurfaceD3D.h"
24#include "libANGLE/renderer/d3d/TextureStorage.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
Geoff Lang0a4f1e22014-12-17 12:33:26 -050032gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const uint8_t **pointerOut)
Jamie Madillc751d1e2014-10-21 17:46:29 -040033{
34 if (unpack.pixelBuffer.id() != 0)
35 {
36 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
37 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
38 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
39
40 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
41 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
Jamie Madill9ae396b2014-10-21 17:46:30 -040042 BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation());
43 ASSERT(bufferD3D);
Jamie Madillc751d1e2014-10-21 17:46:29 -040044 const uint8_t *bufferData = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -040045 gl::Error error = bufferD3D->getData(&bufferData);
Jamie Madillc751d1e2014-10-21 17:46:29 -040046 if (error.isError())
47 {
48 return error;
49 }
50
51 *pointerOut = bufferData + offset;
52 }
53 else
54 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -050055 *pointerOut = pixels;
Jamie Madillc751d1e2014-10-21 17:46:29 -040056 }
57
58 return gl::Error(GL_NO_ERROR);
59}
60
Brandon Jonesf47bebc2014-07-09 14:28:42 -070061bool IsRenderTargetUsage(GLenum usage)
62{
63 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
64}
65
Jamie Madillc751d1e2014-10-21 17:46:29 -040066}
67
Jamie Madill93e13fb2014-11-06 15:27:25 -050068TextureD3D::TextureD3D(RendererD3D *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 : mRenderer(renderer),
70 mUsage(GL_NONE),
71 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040072 mImmutable(false),
73 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070074{
75}
76
77TextureD3D::~TextureD3D()
78{
79}
80
Brandon Jones6053a522014-07-25 16:22:09 -070081TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
82{
83 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
84 return static_cast<TextureD3D*>(texture);
85}
86
Jamie Madill2f06dbf2014-09-18 15:08:50 -040087TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070088{
89 // ensure the underlying texture is created
90 initializeStorage(false);
91
Jamie Madill98553e32014-09-30 16:33:50 -040092 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070093 {
94 updateStorage();
95 }
96
Jamie Madill98553e32014-09-30 16:33:50 -040097 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070098}
99
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700100GLint TextureD3D::getBaseLevelWidth() const
101{
Geoff Langb4dedf32015-01-05 14:08:53 -0500102 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700103 return (baseImage ? baseImage->getWidth() : 0);
104}
105
106GLint TextureD3D::getBaseLevelHeight() const
107{
Geoff Langb4dedf32015-01-05 14:08:53 -0500108 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700109 return (baseImage ? baseImage->getHeight() : 0);
110}
111
112GLint TextureD3D::getBaseLevelDepth() const
113{
Geoff Langb4dedf32015-01-05 14:08:53 -0500114 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700115 return (baseImage ? baseImage->getDepth() : 0);
116}
117
118// Note: "base level image" is loosely defined to be any image from the base level,
119// where in the base of 2D array textures and cube maps there are several. Don't use
120// the base level image for anything except querying texture format and size.
121GLenum TextureD3D::getBaseLevelInternalFormat() const
122{
Geoff Langb4dedf32015-01-05 14:08:53 -0500123 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
125}
126
Geoff Langb4dedf32015-01-05 14:08:53 -0500127bool TextureD3D::shouldUseSetData(const ImageD3D *image) const
Jamie Madillec6de4e2014-10-20 10:59:56 -0400128{
129 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
130 {
131 return false;
132 }
133
134 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
135
136 // We can only handle full updates for depth-stencil textures, so to avoid complications
137 // disable them entirely.
138 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
139 {
140 return false;
141 }
142
143 // TODO(jmadill): Handle compressed internal formats
144 return (mTexStorage && !internalFormat.compressed);
145}
146
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500147gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
Geoff Langb4dedf32015-01-05 14:08:53 -0500149 ImageD3D *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400150 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400151
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152 // No-op
153 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
154 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400155 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700156 }
157
158 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
159 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill9aca0592014-10-06 16:26:59 -0400160 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400161 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
162 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400164 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 }
166
167 if (pixelData != NULL)
168 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400169 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400170 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400171 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400172 }
173 else
174 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500175 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
176 error = image->loadData(fullImageArea, unpack.alignment, type, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400177 }
178
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400179 if (error.isError())
180 {
181 return error;
182 }
183
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700184 mDirtyImages = true;
185 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400186
187 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700188}
189
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500190gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type,
191 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700192{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700193 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400194 const uint8_t *pixelData = NULL;
195 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
196 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700197 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400198 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700199 }
200
201 if (pixelData != NULL)
202 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500203 ImageD3D *image = getImage(index);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400204 ASSERT(image);
205
Jamie Madillec6de4e2014-10-20 10:59:56 -0400206 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400207 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500208 return mTexStorage->setData(index, image, &area, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 }
210
Austin Kinrossc67e6e92015-01-21 16:01:07 -0800211 error = image->loadData(area, unpack.alignment, type, pixelData);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400212 if (error.isError())
213 {
214 return error;
215 }
216
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500217 error = commitRegion(index, area);
Jamie Madille6b6da02014-10-02 11:03:14 -0400218 if (error.isError())
219 {
220 return error;
221 }
222
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700223 mDirtyImages = true;
224 }
225
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400226 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227}
228
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500229gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700230{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400231 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
232 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
233 const uint8_t *pixelData = NULL;
234 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
235 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700236 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400237 return error;
238 }
239
240 if (pixelData != NULL)
241 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500242 ImageD3D *image = getImage(index);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500243 ASSERT(image);
244
245 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
Austin Kinrossc67e6e92015-01-21 16:01:07 -0800246 error = image->loadCompressedData(fullImageArea, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400247 if (error.isError())
248 {
249 return error;
250 }
251
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700252 mDirtyImages = true;
253 }
Geoff Langb5348332014-09-02 13:16:34 -0400254
255 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700256}
257
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500258gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format,
259 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700260{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400261 const uint8_t *pixelData = NULL;
262 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
263 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700264 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400265 return error;
266 }
267
268 if (pixelData != NULL)
269 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500270 ImageD3D *image = getImage(index);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500271 ASSERT(image);
272
Austin Kinrossc67e6e92015-01-21 16:01:07 -0800273 error = image->loadCompressedData(area, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400274 if (error.isError())
275 {
276 return error;
277 }
278
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700279 mDirtyImages = true;
280 }
281
Geoff Langb5348332014-09-02 13:16:34 -0400282 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700283}
284
285bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
286{
287 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
288}
289
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500290gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
Geoff Langc2e75af2015-01-05 14:26:24 -0500291 GLenum sizedInternalFormat, GLenum type, RenderTargetD3D *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700292{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400293 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
295 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400296 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700297 }
298
299 // In order to perform the fast copy through the shader, we must have the right format, and be able
300 // to create a render target.
301 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
302
Jacek Cabana5521de2014-10-01 17:23:46 +0200303 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700304
Geoff Langae5122c2014-08-27 14:08:43 -0400305 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
306 if (error.isError())
307 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400308 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400309 }
310
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400311 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700312}
313
314GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
315{
316 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
317 {
318 // Maximum number of levels
319 return gl::log2(std::max(std::max(width, height), depth)) + 1;
320 }
321 else
322 {
323 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
324 return 1;
325 }
326}
327
328int TextureD3D::mipLevels() const
329{
330 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
331}
332
Jamie Madill98553e32014-09-30 16:33:50 -0400333TextureStorage *TextureD3D::getStorage()
334{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400335 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400336 return mTexStorage;
337}
338
Geoff Langb4dedf32015-01-05 14:08:53 -0500339ImageD3D *TextureD3D::getBaseLevelImage() const
Jamie Madill3269bcb2014-09-30 16:33:52 -0400340{
341 return getImage(getImageIndex(0, 0));
342}
343
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400344gl::Error TextureD3D::generateMipmaps()
Jamie Madill4aa79e12014-09-29 10:46:14 -0400345{
Jamie Madill9aca0592014-10-06 16:26:59 -0400346 GLint mipCount = mipLevels();
347
348 if (mipCount == 1)
349 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400350 return gl::Error(GL_NO_ERROR); // no-op
Jamie Madill9aca0592014-10-06 16:26:59 -0400351 }
352
Austin Kinross215b37a2014-12-22 12:56:07 -0800353 if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
354 {
355 // Switch to using the mipmapped texture.
356 gl::Error error = getNativeTexture()->useLevelZeroWorkaroundTexture(false);
357 if (error.isError())
358 {
359 return error;
360 }
361 }
362
Austin Kinross62815bf2015-01-15 16:32:36 -0800363 // Set up proper mipmap chain in our Image array.
364 initMipmapsImages();
365
Jamie Madill4aa79e12014-09-29 10:46:14 -0400366 // We know that all layers have the same dimension, for the texture to be complete
367 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400368
Jamie Madill9aca0592014-10-06 16:26:59 -0400369 // When making mipmaps with the setData workaround enabled, the texture storage has
370 // the image data already. For non-render-target storage, we have to pull it out into
371 // an image layer.
372 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
373 {
374 if (!mTexStorage->isRenderTarget())
375 {
376 // Copy from the storage mip 0 to Image mip 0
377 for (GLint layer = 0; layer < layerCount; ++layer)
378 {
379 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400380
Geoff Langb4dedf32015-01-05 14:08:53 -0500381 ImageD3D *image = getImage(srcIndex);
Jamie Madill9aca0592014-10-06 16:26:59 -0400382 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500383 gl::Offset offset(0, 0, 0);
384 gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400385 if (error.isError())
386 {
387 return error;
388 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400389 }
390 }
391 else
392 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400393 gl::Error error = updateStorage();
394 if (error.isError())
395 {
396 return error;
397 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400398 }
399 }
400
Austin Kinross215b37a2014-12-22 12:56:07 -0800401 // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to zeroMaxLodWorkaround.
402 // The restriction is because Feature Level 9_3 can't create SRVs on individual levels of the texture.
403 // As a result, even if the storage is a rendertarget, we can't use the GPU to generate the mipmaps without further work.
404 // The D3D9 renderer works around this by copying each level of the texture into its own single-layer GPU texture (in Blit9::boxFilter).
405 // Feature Level 9_3 could do something similar, or it could continue to use CPU-side mipmap generation, or something else.
406 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && !(mRenderer->getWorkarounds().zeroMaxLodWorkaround));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400407
408 for (GLint layer = 0; layer < layerCount; ++layer)
409 {
410 for (GLint mip = 1; mip < mipCount; ++mip)
411 {
412 ASSERT(getLayerCount(mip) == layerCount);
413
414 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
415 gl::ImageIndex destIndex = getImageIndex(mip, layer);
416
417 if (renderableStorage)
418 {
419 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400420 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
421 if (error.isError())
422 {
423 return error;
424 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400425 }
426 else
427 {
428 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400429 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
430 if (error.isError())
431 {
432 return error;
433 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400434 }
435 }
436 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400437
438 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400439}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440
Jamie Madill135570a2014-09-30 16:33:51 -0400441bool TextureD3D::isBaseImageZeroSize() const
442{
Geoff Langb4dedf32015-01-05 14:08:53 -0500443 ImageD3D *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400444
445 if (!baseImage || baseImage->getWidth() <= 0)
446 {
447 return true;
448 }
449
Geoff Lang691e58c2014-12-19 17:03:25 -0500450 if (!gl::IsCubeMapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
Jamie Madill135570a2014-09-30 16:33:51 -0400451 {
452 return true;
453 }
454
455 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
456 {
457 return true;
458 }
459
460 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
461 {
462 return true;
463 }
464
465 return false;
466}
467
Geoff Langef7b0162014-09-04 13:29:23 -0400468gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400469{
Geoff Langef7b0162014-09-04 13:29:23 -0400470 gl::Error error = initializeStorage(true);
471 if (error.isError())
472 {
473 return error;
474 }
Jamie Madill135570a2014-09-30 16:33:51 -0400475
476 if (!isBaseImageZeroSize())
477 {
478 ASSERT(mTexStorage);
479 if (!mTexStorage->isRenderTarget())
480 {
Geoff Langef7b0162014-09-04 13:29:23 -0400481 TextureStorage *newRenderTargetStorage = NULL;
482 error = createCompleteStorage(true, &newRenderTargetStorage);
483 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400484 {
Geoff Langef7b0162014-09-04 13:29:23 -0400485 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400486 }
487
Geoff Langef7b0162014-09-04 13:29:23 -0400488 error = mTexStorage->copyToStorage(newRenderTargetStorage);
489 if (error.isError())
490 {
491 SafeDelete(newRenderTargetStorage);
492 return error;
493 }
494
495 error = setCompleteTexStorage(newRenderTargetStorage);
496 if (error.isError())
497 {
498 SafeDelete(newRenderTargetStorage);
499 return error;
500 }
Jamie Madill135570a2014-09-30 16:33:51 -0400501 }
502 }
503
Geoff Langef7b0162014-09-04 13:29:23 -0400504 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400505}
506
Jamie Madille76bdda2014-10-20 17:13:52 -0400507bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
508{
Geoff Langb4dedf32015-01-05 14:08:53 -0500509 ImageD3D *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400510 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
511 return (image->isRenderableFormat() && levelsComplete);
512}
513
Jamie Madill710e5772014-10-20 17:13:53 -0400514gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
515{
516 if (mTexStorage)
517 {
518 ASSERT(isValidIndex(index));
Geoff Langb4dedf32015-01-05 14:08:53 -0500519 ImageD3D *image = getImage(index);
520 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Jamie Madill710e5772014-10-20 17:13:53 -0400521 if (error.isError())
522 {
523 return error;
524 }
525
526 image->markClean();
527 }
528
529 return gl::Error(GL_NO_ERROR);
530}
531
Jamie Madill93e13fb2014-11-06 15:27:25 -0500532TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400533 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534{
535 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
536 {
Geoff Langb4dedf32015-01-05 14:08:53 -0500537 mImageArray[i] = renderer->createImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538 }
539}
540
541TextureD3D_2D::~TextureD3D_2D()
542{
Austin Kinross69822602014-08-12 15:51:37 -0700543 // Delete the Images before the TextureStorage.
544 // Images might be relying on the TextureStorage for some of their data.
545 // 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 -0700546 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
547 {
548 delete mImageArray[i];
549 }
Austin Kinross69822602014-08-12 15:51:37 -0700550
551 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552}
553
Geoff Langb4dedf32015-01-05 14:08:53 -0500554ImageD3D *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555{
556 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700557 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558 return mImageArray[level];
559}
560
Geoff Langb4dedf32015-01-05 14:08:53 -0500561ImageD3D *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -0400562{
563 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400564 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400565 ASSERT(index.type == GL_TEXTURE_2D);
566 return mImageArray[index.mipIndex];
567}
568
Brandon Jonescef06ff2014-08-05 13:27:48 -0700569GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700570{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700571 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
572 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700573}
574
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575GLsizei TextureD3D_2D::getWidth(GLint level) const
576{
577 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
578 return mImageArray[level]->getWidth();
579 else
580 return 0;
581}
582
583GLsizei TextureD3D_2D::getHeight(GLint level) const
584{
585 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
586 return mImageArray[level]->getHeight();
587 else
588 return 0;
589}
590
591GLenum TextureD3D_2D::getInternalFormat(GLint level) const
592{
593 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
594 return mImageArray[level]->getInternalFormat();
595 else
596 return GL_NONE;
597}
598
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599bool TextureD3D_2D::isDepth(GLint level) const
600{
Geoff Lang5d601382014-07-22 15:14:06 -0400601 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700602}
603
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500604gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
605 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500607 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700608
Geoff Lang5d601382014-07-22 15:14:06 -0400609 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
610
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700611 bool fastUnpacked = false;
612
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500613 redefineImage(level, sizedInternalFormat, size);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700614
Jamie Madillba6bc952014-10-06 10:56:22 -0400615 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
616
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700617 // Attempt a fast gpu copy of the pixel data to the surface
618 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
619 {
620 // Will try to create RT storage if it does not exist
Geoff Langc2e75af2015-01-05 14:26:24 -0500621 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -0400622 gl::Error error = getRenderTarget(index, &destRenderTarget);
623 if (error.isError())
624 {
625 return error;
626 }
627
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700628 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
629
Geoff Lang64f23f62014-09-10 14:40:12 -0400630 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
631 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400633 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400635
636 // Ensure we don't overwrite our newly initialized data
637 mImageArray[level]->markClean();
638
639 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700640 }
641
642 if (!fastUnpacked)
643 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500644 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400645 if (error.isError())
646 {
647 return error;
648 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700649 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400650
651 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652}
653
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500654gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
655 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500657 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700658
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700659 bool fastUnpacked = false;
660
Jamie Madillac7579c2014-09-17 16:59:33 -0400661 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
663 {
Geoff Langc2e75af2015-01-05 14:26:24 -0500664 RenderTargetD3D *renderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -0400665 gl::Error error = getRenderTarget(index, &renderTarget);
666 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400668 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400670
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500671 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -0400672 if (error.isError())
673 {
674 return error;
675 }
676
677 // Ensure we don't overwrite our newly initialized data
678 mImageArray[level]->markClean();
679
680 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700681 }
682
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400683 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700684 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500685 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400687
688 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700689}
690
Brandon Jonescef06ff2014-08-05 13:27:48 -0700691
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500692gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
693 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
694{
695 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
696
697 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
698 redefineImage(level, internalFormat, size);
699
700 return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels);
701}
702
703gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
704 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
705{
706 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
707
708 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
709 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -0400710 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700711 {
Geoff Langb5348332014-09-02 13:16:34 -0400712 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700713 }
Geoff Langb5348332014-09-02 13:16:34 -0400714
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500715 return commitRegion(index, area);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700716}
717
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500718gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
719 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700720{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700721 ASSERT(target == GL_TEXTURE_2D);
722
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500723 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
724 redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1));
Brandon Jonescef06ff2014-08-05 13:27:48 -0700725
Jamie Madille76bdda2014-10-20 17:13:52 -0400726 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500727 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400728
Austin Kinross62815bf2015-01-15 16:32:36 -0800729 // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
730 // so we should use the non-rendering copy path.
731 if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
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 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -0800753 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
Austin Kinross62815bf2015-01-15 16:32:36 -0800774 // If the zero max LOD workaround is active, then we can't sample from individual layers of the framebuffer in shaders,
775 // so we should use the non-rendering copy path.
776 if (!canCreateRenderTargetForImage(index) || mRenderer->getWorkarounds().zeroMaxLodWorkaround)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700777 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500778 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400779 if (error.isError())
780 {
781 return error;
782 }
783
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700784 mDirtyImages = true;
785 }
786 else
787 {
Geoff Langef7b0162014-09-04 13:29:23 -0400788 gl::Error error = ensureRenderTarget();
789 if (error.isError())
790 {
791 return error;
792 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793
794 if (isValidLevel(level))
795 {
Geoff Langef7b0162014-09-04 13:29:23 -0400796 error = updateStorageLevel(level);
797 if (error.isError())
798 {
799 return error;
800 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700801
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500802 error = mRenderer->copyImage2D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -0400803 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500804 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400805 if (error.isError())
806 {
807 return error;
808 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809 }
810 }
Geoff Langef7b0162014-09-04 13:29:23 -0400811
812 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813}
814
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500815gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700816{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500817 ASSERT(GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700818
Geoff Lang8fed1f72015-01-09 11:09:33 -0500819 for (size_t level = 0; level < levels; level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700820 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500821 gl::Extents levelSize(std::max(1, size.width >> level),
822 std::max(1, size.height >> level),
823 1);
824 mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700825 }
826
827 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
828 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500829 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700830 }
831
Geoff Lang1f8532b2014-09-05 09:46:13 -0400832 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400833 bool renderTarget = IsRenderTargetUsage(mUsage);
Austin Kinross215b37a2014-12-22 12:56:07 -0800834 TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400835
836 gl::Error error = setCompleteTexStorage(storage);
837 if (error.isError())
838 {
839 SafeDelete(storage);
840 return error;
841 }
842
843 mImmutable = true;
844
845 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700846}
847
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700848void TextureD3D_2D::bindTexImage(egl::Surface *surface)
849{
850 GLenum internalformat = surface->getFormat();
851
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500852 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
853 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700854
855 if (mTexStorage)
856 {
857 SafeDelete(mTexStorage);
858 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400859
Jamie Madillfb0580a2014-11-27 14:03:52 -0500860 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
861 ASSERT(surfaceD3D);
862
863 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864
865 mDirtyImages = true;
866}
867
868void TextureD3D_2D::releaseTexImage()
869{
870 if (mTexStorage)
871 {
872 SafeDelete(mTexStorage);
873 }
874
875 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
876 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500877 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700878 }
879}
880
Jamie Madill4aa79e12014-09-29 10:46:14 -0400881void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700883 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700885 for (int level = 1; level < levelCount; level++)
886 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500887 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
888 std::max(getBaseLevelHeight() >> level, 1),
889 1);
890
891 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700892 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700893}
894
Jamie Madillac7579c2014-09-17 16:59:33 -0400895unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700896{
Jamie Madillac7579c2014-09-17 16:59:33 -0400897 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400898 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700899}
900
Geoff Langc2e75af2015-01-05 14:26:24 -0500901gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700902{
Jamie Madillac7579c2014-09-17 16:59:33 -0400903 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700904
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700905 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400906 gl::Error error = ensureRenderTarget();
907 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700908 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400909 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700910 }
911
Geoff Langef7b0162014-09-04 13:29:23 -0400912 error = updateStorageLevel(index.mipIndex);
913 if (error.isError())
914 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400915 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400916 }
917
Geoff Lang64f23f62014-09-10 14:40:12 -0400918 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919}
920
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700921bool TextureD3D_2D::isValidLevel(int level) const
922{
923 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
924}
925
926bool TextureD3D_2D::isLevelComplete(int level) const
927{
928 if (isImmutable())
929 {
930 return true;
931 }
932
Geoff Langb4dedf32015-01-05 14:08:53 -0500933 const ImageD3D *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700934
935 GLsizei width = baseImage->getWidth();
936 GLsizei height = baseImage->getHeight();
937
938 if (width <= 0 || height <= 0)
939 {
940 return false;
941 }
942
943 // The base image level is complete if the width and height are positive
944 if (level == 0)
945 {
946 return true;
947 }
948
949 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700950 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700951
952 if (image->getInternalFormat() != baseImage->getInternalFormat())
953 {
954 return false;
955 }
956
957 if (image->getWidth() != std::max(1, width >> level))
958 {
959 return false;
960 }
961
962 if (image->getHeight() != std::max(1, height >> level))
963 {
964 return false;
965 }
966
967 return true;
968}
969
Jamie Madille76bdda2014-10-20 17:13:52 -0400970bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
971{
972 return isLevelComplete(index.mipIndex);
973}
974
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700975// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400976gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700977{
978 // Only initialize the first time this texture is used as a render target or shader resource
979 if (mTexStorage)
980 {
Geoff Langef7b0162014-09-04 13:29:23 -0400981 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700982 }
983
984 // do not attempt to create storage for nonexistant data
985 if (!isLevelComplete(0))
986 {
Geoff Langef7b0162014-09-04 13:29:23 -0400987 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700988 }
989
990 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
991
Geoff Langef7b0162014-09-04 13:29:23 -0400992 TextureStorage *storage = NULL;
993 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
994 if (error.isError())
995 {
996 return error;
997 }
998
999 error = setCompleteTexStorage(storage);
1000 if (error.isError())
1001 {
1002 SafeDelete(storage);
1003 return error;
1004 }
1005
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001006 ASSERT(mTexStorage);
1007
1008 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001009 error = updateStorage();
1010 if (error.isError())
1011 {
1012 return error;
1013 }
1014
1015 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001016}
1017
Geoff Langef7b0162014-09-04 13:29:23 -04001018gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001019{
1020 GLsizei width = getBaseLevelWidth();
1021 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001022 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001023
1024 ASSERT(width > 0 && height > 0);
1025
1026 // use existing storage level count, when previously specified by TexStorage*D
1027 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1028
Austin Kinross215b37a2014-12-22 12:56:07 -08001029 bool hintLevelZeroOnly = false;
1030 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1031 {
1032 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
1033 // Otherwise, it should use the level-zero-only texture.
1034 hintLevelZeroOnly = true;
Austin Kinross62815bf2015-01-15 16:32:36 -08001035 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
Austin Kinross215b37a2014-12-22 12:56:07 -08001036 {
1037 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
Austin Kinross215b37a2014-12-22 12:56:07 -08001038 }
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);
Austin Kinross62815bf2015-01-15 16:32:36 -08001384
1385 TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001386
1387 gl::Error error = setCompleteTexStorage(storage);
1388 if (error.isError())
1389 {
1390 SafeDelete(storage);
1391 return error;
1392 }
1393
1394 mImmutable = true;
1395
1396 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001397}
1398
Brandon Jones0511e802014-07-14 16:27:26 -07001399// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1400bool TextureD3D_Cube::isCubeComplete() const
1401{
1402 int baseWidth = getBaseLevelWidth();
1403 int baseHeight = getBaseLevelHeight();
1404 GLenum baseFormat = getBaseLevelInternalFormat();
1405
1406 if (baseWidth <= 0 || baseWidth != baseHeight)
1407 {
1408 return false;
1409 }
1410
1411 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1412 {
1413 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1414
1415 if (faceBaseImage.getWidth() != baseWidth ||
1416 faceBaseImage.getHeight() != baseHeight ||
1417 faceBaseImage.getInternalFormat() != baseFormat )
1418 {
1419 return false;
1420 }
1421 }
1422
1423 return true;
1424}
1425
Brandon Jones6053a522014-07-25 16:22:09 -07001426void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1427{
1428 UNREACHABLE();
1429}
1430
1431void TextureD3D_Cube::releaseTexImage()
1432{
1433 UNREACHABLE();
1434}
1435
1436
Jamie Madill4aa79e12014-09-29 10:46:14 -04001437void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001438{
1439 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1440 int levelCount = mipLevels();
1441 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1442 {
1443 for (int level = 1; level < levelCount; level++)
1444 {
1445 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001446 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1447 gl::Extents(faceLevelSize, faceLevelSize, 1));
Brandon Jones0511e802014-07-14 16:27:26 -07001448 }
1449 }
Brandon Jones0511e802014-07-14 16:27:26 -07001450}
1451
Jamie Madillac7579c2014-09-17 16:59:33 -04001452unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001453{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001454 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001455}
1456
Geoff Langc2e75af2015-01-05 14:26:24 -05001457gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001458{
Geoff Lang691e58c2014-12-19 17:03:25 -05001459 ASSERT(gl::IsCubeMapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001460
1461 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001462 gl::Error error = ensureRenderTarget();
1463 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001464 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001465 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001466 }
1467
Geoff Langef7b0162014-09-04 13:29:23 -04001468 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1469 if (error.isError())
1470 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001471 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001472 }
1473
Geoff Lang64f23f62014-09-10 14:40:12 -04001474 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001475}
1476
Geoff Langef7b0162014-09-04 13:29:23 -04001477gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001478{
1479 // Only initialize the first time this texture is used as a render target or shader resource
1480 if (mTexStorage)
1481 {
Geoff Langef7b0162014-09-04 13:29:23 -04001482 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001483 }
1484
1485 // do not attempt to create storage for nonexistant data
1486 if (!isFaceLevelComplete(0, 0))
1487 {
Geoff Langef7b0162014-09-04 13:29:23 -04001488 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001489 }
1490
1491 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1492
Geoff Langef7b0162014-09-04 13:29:23 -04001493 TextureStorage *storage = NULL;
1494 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1495 if (error.isError())
1496 {
1497 return error;
1498 }
1499
1500 error = setCompleteTexStorage(storage);
1501 if (error.isError())
1502 {
1503 SafeDelete(storage);
1504 return error;
1505 }
1506
Brandon Jones0511e802014-07-14 16:27:26 -07001507 ASSERT(mTexStorage);
1508
1509 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001510 error = updateStorage();
1511 if (error.isError())
1512 {
1513 return error;
1514 }
1515
1516 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001517}
1518
Geoff Langef7b0162014-09-04 13:29:23 -04001519gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001520{
1521 GLsizei size = getBaseLevelWidth();
1522
1523 ASSERT(size > 0);
1524
1525 // use existing storage level count, when previously specified by TexStorage*D
1526 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1527
Austin Kinross62815bf2015-01-15 16:32:36 -08001528 bool hintLevelZeroOnly = false;
1529 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1530 {
1531 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage should use the mipped texture to begin with.
1532 // Otherwise, it should use the level-zero-only texture.
1533 hintLevelZeroOnly = true;
1534 for (int faceIndex = 0; faceIndex < 6 && hintLevelZeroOnly; faceIndex++)
1535 {
1536 for (int level = 1; level < levels && hintLevelZeroOnly; level++)
1537 {
1538 hintLevelZeroOnly = !(mImageArray[faceIndex][level]->isDirty() && isFaceLevelComplete(faceIndex, level));
1539 }
1540 }
1541 }
1542
Geoff Langef7b0162014-09-04 13:29:23 -04001543 // TODO (geofflang): detect if storage creation succeeded
Austin Kinross62815bf2015-01-15 16:32:36 -08001544 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels, hintLevelZeroOnly);
Geoff Langef7b0162014-09-04 13:29:23 -04001545
1546 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001547}
1548
Geoff Langef7b0162014-09-04 13:29:23 -04001549gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001550{
Geoff Langef7b0162014-09-04 13:29:23 -04001551 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001552 {
1553 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1554 {
Geoff Langef7b0162014-09-04 13:29:23 -04001555 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001556 {
Geoff Langef7b0162014-09-04 13:29:23 -04001557 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1558 if (error.isError())
1559 {
1560 return error;
1561 }
Brandon Jones0511e802014-07-14 16:27:26 -07001562 }
1563 }
1564 }
1565
Geoff Langef7b0162014-09-04 13:29:23 -04001566 SafeDelete(mTexStorage);
1567 mTexStorage = newCompleteTexStorage;
1568
Brandon Jones0511e802014-07-14 16:27:26 -07001569 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001570 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001571}
1572
Geoff Langef7b0162014-09-04 13:29:23 -04001573gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001574{
1575 ASSERT(mTexStorage != NULL);
1576 GLint storageLevels = mTexStorage->getLevelCount();
1577 for (int face = 0; face < 6; face++)
1578 {
1579 for (int level = 0; level < storageLevels; level++)
1580 {
1581 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1582 {
Geoff Langef7b0162014-09-04 13:29:23 -04001583 gl::Error error = updateStorageFaceLevel(face, level);
1584 if (error.isError())
1585 {
1586 return error;
1587 }
Brandon Jones0511e802014-07-14 16:27:26 -07001588 }
1589 }
1590 }
Geoff Langef7b0162014-09-04 13:29:23 -04001591
1592 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001593}
1594
Brandon Jones0511e802014-07-14 16:27:26 -07001595bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1596{
1597 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1598}
1599
Brandon Jones0511e802014-07-14 16:27:26 -07001600bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1601{
1602 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1603
1604 if (isImmutable())
1605 {
1606 return true;
1607 }
1608
1609 int baseSize = getBaseLevelWidth();
1610
1611 if (baseSize <= 0)
1612 {
1613 return false;
1614 }
1615
1616 // "isCubeComplete" checks for base level completeness and we must call that
1617 // to determine if any face at level 0 is complete. We omit that check here
1618 // to avoid re-checking cube-completeness for every face at level 0.
1619 if (level == 0)
1620 {
1621 return true;
1622 }
1623
1624 // Check that non-zero levels are consistent with the base level.
1625 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1626
1627 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1628 {
1629 return false;
1630 }
1631
1632 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1633 {
1634 return false;
1635 }
1636
1637 return true;
1638}
1639
Jamie Madille76bdda2014-10-20 17:13:52 -04001640bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1641{
1642 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1643}
1644
Geoff Langef7b0162014-09-04 13:29:23 -04001645gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001646{
1647 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1648 ImageD3D *image = mImageArray[faceIndex][level];
1649
1650 if (image->isDirty())
1651 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001652 GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001653 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1654 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001655 gl::Error error = commitRegion(index, region);
1656 if (error.isError())
1657 {
1658 return error;
1659 }
Brandon Jones0511e802014-07-14 16:27:26 -07001660 }
Geoff Langef7b0162014-09-04 13:29:23 -04001661
1662 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001663}
1664
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001665void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001666{
1667 // If there currently is a corresponding storage texture image, it has these parameters
1668 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1669 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1670 const GLenum storageFormat = getBaseLevelInternalFormat();
1671
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001672 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001673
1674 if (mTexStorage)
1675 {
1676 const int storageLevels = mTexStorage->getLevelCount();
1677
1678 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001679 size.width != storageWidth ||
1680 size.height != storageHeight ||
Brandon Jones0511e802014-07-14 16:27:26 -07001681 internalformat != storageFormat) // Discard mismatched storage
1682 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08001683 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
Brandon Jones0511e802014-07-14 16:27:26 -07001684 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08001685 for (int dirtyFace = 0; dirtyFace < 6; faceIndex++)
Brandon Jones0511e802014-07-14 16:27:26 -07001686 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08001687 mImageArray[dirtyFace][dirtyLevel]->markDirty();
Brandon Jones0511e802014-07-14 16:27:26 -07001688 }
1689 }
1690
1691 SafeDelete(mTexStorage);
1692
1693 mDirtyImages = true;
1694 }
1695 }
1696}
1697
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001698gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1699{
1700 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1701}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001702
Jamie Madillcb83dc12014-09-29 10:46:12 -04001703gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1704{
1705 // The "layer" of the image index corresponds to the cube face
Geoff Lang691e58c2014-12-19 17:03:25 -05001706 return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip);
Jamie Madillcb83dc12014-09-29 10:46:12 -04001707}
1708
Jamie Madill710e5772014-10-20 17:13:53 -04001709bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1710{
Geoff Lang691e58c2014-12-19 17:03:25 -05001711 return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) &&
Jamie Madill710e5772014-10-20 17:13:53 -04001712 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1713}
1714
Jamie Madill93e13fb2014-11-06 15:27:25 -05001715TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001716 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001717{
1718 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1719 {
Geoff Langb4dedf32015-01-05 14:08:53 -05001720 mImageArray[i] = renderer->createImage();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001721 }
1722}
1723
1724TextureD3D_3D::~TextureD3D_3D()
1725{
Austin Kinross69822602014-08-12 15:51:37 -07001726 // Delete the Images before the TextureStorage.
1727 // Images might be relying on the TextureStorage for some of their data.
1728 // 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 -07001729 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1730 {
1731 delete mImageArray[i];
1732 }
Austin Kinross69822602014-08-12 15:51:37 -07001733
1734 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001735}
1736
Geoff Langb4dedf32015-01-05 14:08:53 -05001737ImageD3D *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001738{
1739 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001740 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741 return mImageArray[level];
1742}
1743
Geoff Langb4dedf32015-01-05 14:08:53 -05001744ImageD3D *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04001745{
1746 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001747 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001748 ASSERT(index.type == GL_TEXTURE_3D);
1749 return mImageArray[index.mipIndex];
1750}
1751
Brandon Jonescef06ff2014-08-05 13:27:48 -07001752GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001753{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001754 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1755 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001756}
1757
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758GLsizei TextureD3D_3D::getWidth(GLint level) const
1759{
1760 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1761 return mImageArray[level]->getWidth();
1762 else
1763 return 0;
1764}
1765
1766GLsizei TextureD3D_3D::getHeight(GLint level) const
1767{
1768 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1769 return mImageArray[level]->getHeight();
1770 else
1771 return 0;
1772}
1773
1774GLsizei TextureD3D_3D::getDepth(GLint level) const
1775{
1776 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1777 return mImageArray[level]->getDepth();
1778 else
1779 return 0;
1780}
1781
1782GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1783{
1784 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1785 return mImageArray[level]->getInternalFormat();
1786 else
1787 return GL_NONE;
1788}
1789
1790bool TextureD3D_3D::isDepth(GLint level) const
1791{
Geoff Lang5d601382014-07-22 15:14:06 -04001792 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001793}
1794
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001795gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1796 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001797{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001798 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001799 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1800
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001801 redefineImage(level, sizedInternalFormat, size);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802
1803 bool fastUnpacked = false;
1804
Jamie Madillba6bc952014-10-06 10:56:22 -04001805 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1806
Brandon Jones78b1acd2014-07-15 15:33:07 -07001807 // 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 -05001808 if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 {
1810 // Will try to create RT storage if it does not exist
Geoff Langc2e75af2015-01-05 14:26:24 -05001811 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -04001812 gl::Error error = getRenderTarget(index, &destRenderTarget);
1813 if (error.isError())
1814 {
1815 return error;
1816 }
1817
Brandon Jones78b1acd2014-07-15 15:33:07 -07001818 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1819
Geoff Lang64f23f62014-09-10 14:40:12 -04001820 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1821 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001822 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001823 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001825
1826 // Ensure we don't overwrite our newly initialized data
1827 mImageArray[level]->markClean();
1828
1829 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830 }
1831
1832 if (!fastUnpacked)
1833 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001834 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001835 if (error.isError())
1836 {
1837 return error;
1838 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001839 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001840
1841 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001842}
1843
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001844gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1845 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001846{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001847 ASSERT(target == GL_TEXTURE_3D);
1848
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849 bool fastUnpacked = false;
1850
Jamie Madillac7579c2014-09-17 16:59:33 -04001851 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1852
Brandon Jones78b1acd2014-07-15 15:33:07 -07001853 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1854 if (isFastUnpackable(unpack, getInternalFormat(level)))
1855 {
Geoff Langc2e75af2015-01-05 14:26:24 -05001856 RenderTargetD3D *destRenderTarget = NULL;
Geoff Lang64f23f62014-09-10 14:40:12 -04001857 gl::Error error = getRenderTarget(index, &destRenderTarget);
1858 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001859 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001860 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001862
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001863 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -04001864 if (error.isError())
1865 {
1866 return error;
1867 }
1868
1869 // Ensure we don't overwrite our newly initialized data
1870 mImageArray[level]->markClean();
1871
1872 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001873 }
1874
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001875 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001876 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001877 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001878 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001879
1880 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001881}
1882
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001883gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1884 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001885{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001886 ASSERT(target == GL_TEXTURE_3D);
1887
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001888 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1889 redefineImage(level, internalFormat, size);
1890
1891 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1892 return TextureD3D::setCompressedImage(index, unpack, pixels);
1893}
1894
1895gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1896 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1897{
1898 ASSERT(target == GL_TEXTURE_3D);
1899
1900 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1901 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001902 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001903 {
Geoff Langb5348332014-09-02 13:16:34 -04001904 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001905 }
Geoff Langb5348332014-09-02 13:16:34 -04001906
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001907 return commitRegion(index, area);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001908}
1909
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001910gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1911 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001912{
1913 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001914 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001915}
1916
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001917gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1918 const gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001919{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001920 ASSERT(target == GL_TEXTURE_3D);
1921
Jamie Madille76bdda2014-10-20 17:13:52 -04001922 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001923
Jamie Madille76bdda2014-10-20 17:13:52 -04001924 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001925 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001926 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001927 if (error.isError())
1928 {
1929 return error;
1930 }
1931
Brandon Jones78b1acd2014-07-15 15:33:07 -07001932 mDirtyImages = true;
1933 }
1934 else
1935 {
Geoff Langef7b0162014-09-04 13:29:23 -04001936 gl::Error error = ensureRenderTarget();
1937 if (error.isError())
1938 {
1939 return error;
1940 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001941
1942 if (isValidLevel(level))
1943 {
Geoff Langef7b0162014-09-04 13:29:23 -04001944 error = updateStorageLevel(level);
1945 if (error.isError())
1946 {
1947 return error;
1948 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001950 error = mRenderer->copyImage3D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -04001951 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001952 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001953 if (error.isError())
1954 {
1955 return error;
1956 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001957 }
1958 }
Geoff Langef7b0162014-09-04 13:29:23 -04001959
1960 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001961}
1962
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001963gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001964{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001965 ASSERT(target == GL_TEXTURE_3D);
1966
Geoff Lang8fed1f72015-01-09 11:09:33 -05001967 for (size_t level = 0; level < levels; level++)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001968 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001969 gl::Extents levelSize(std::max(1, size.width >> level),
1970 std::max(1, size.height >> level),
1971 std::max(1, size.depth >> level));
1972 mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001973 }
1974
1975 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1976 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001977 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001978 }
1979
Geoff Lang1f8532b2014-09-05 09:46:13 -04001980 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001981 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001982 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001983
1984 gl::Error error = setCompleteTexStorage(storage);
1985 if (error.isError())
1986 {
1987 SafeDelete(storage);
1988 return error;
1989 }
1990
1991 mImmutable = true;
1992
1993 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001994}
1995
Brandon Jones6053a522014-07-25 16:22:09 -07001996void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001997{
Brandon Jones6053a522014-07-25 16:22:09 -07001998 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001999}
2000
Brandon Jones6053a522014-07-25 16:22:09 -07002001void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002{
Brandon Jones6053a522014-07-25 16:22:09 -07002003 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002004}
2005
Brandon Jones6053a522014-07-25 16:22:09 -07002006
Jamie Madill4aa79e12014-09-29 10:46:14 -04002007void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002008{
2009 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2010 int levelCount = mipLevels();
2011 for (int level = 1; level < levelCount; level++)
2012 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002013 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
2014 std::max(getBaseLevelHeight() >> level, 1),
2015 std::max(getBaseLevelDepth() >> level, 1));
2016 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002017 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002018}
2019
Jamie Madillac7579c2014-09-17 16:59:33 -04002020unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002021{
Geoff Langef7b0162014-09-04 13:29:23 -04002022 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002023}
2024
Geoff Langc2e75af2015-01-05 14:26:24 -05002025gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002026{
2027 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002028 gl::Error error = ensureRenderTarget();
2029 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002030 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002031 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002032 }
2033
Jamie Madillac7579c2014-09-17 16:59:33 -04002034 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002035 {
Geoff Langef7b0162014-09-04 13:29:23 -04002036 error = updateStorage();
2037 if (error.isError())
2038 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002039 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002040 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002041 }
2042 else
2043 {
Geoff Langef7b0162014-09-04 13:29:23 -04002044 error = updateStorageLevel(index.mipIndex);
2045 if (error.isError())
2046 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002047 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002048 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002049 }
2050
Geoff Lang64f23f62014-09-10 14:40:12 -04002051 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002052}
2053
Geoff Langef7b0162014-09-04 13:29:23 -04002054gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002055{
2056 // Only initialize the first time this texture is used as a render target or shader resource
2057 if (mTexStorage)
2058 {
Geoff Langef7b0162014-09-04 13:29:23 -04002059 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002060 }
2061
2062 // do not attempt to create storage for nonexistant data
2063 if (!isLevelComplete(0))
2064 {
Geoff Langef7b0162014-09-04 13:29:23 -04002065 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002066 }
2067
2068 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2069
Jamie Madill30d6c252014-11-13 10:03:33 -05002070 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002071 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2072 if (error.isError())
2073 {
2074 return error;
2075 }
2076
2077 error = setCompleteTexStorage(storage);
2078 if (error.isError())
2079 {
2080 SafeDelete(storage);
2081 return error;
2082 }
2083
Brandon Jones78b1acd2014-07-15 15:33:07 -07002084 ASSERT(mTexStorage);
2085
2086 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002087 error = updateStorage();
2088 if (error.isError())
2089 {
2090 return error;
2091 }
2092
2093 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002094}
2095
Geoff Langef7b0162014-09-04 13:29:23 -04002096gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002097{
2098 GLsizei width = getBaseLevelWidth();
2099 GLsizei height = getBaseLevelHeight();
2100 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002101 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002102
2103 ASSERT(width > 0 && height > 0 && depth > 0);
2104
2105 // use existing storage level count, when previously specified by TexStorage*D
2106 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2107
Geoff Langef7b0162014-09-04 13:29:23 -04002108 // TODO: Verify creation of the storage succeeded
2109 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2110
2111 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002112}
2113
Geoff Langef7b0162014-09-04 13:29:23 -04002114gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002115{
2116 SafeDelete(mTexStorage);
2117 mTexStorage = newCompleteTexStorage;
2118 mDirtyImages = true;
2119
2120 // We do not support managed 3D storage, as that is D3D9/ES2-only
2121 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002122
2123 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002124}
2125
Geoff Langef7b0162014-09-04 13:29:23 -04002126gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002127{
2128 ASSERT(mTexStorage != NULL);
2129 GLint storageLevels = mTexStorage->getLevelCount();
2130 for (int level = 0; level < storageLevels; level++)
2131 {
2132 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2133 {
Geoff Langef7b0162014-09-04 13:29:23 -04002134 gl::Error error = updateStorageLevel(level);
2135 if (error.isError())
2136 {
2137 return error;
2138 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002139 }
2140 }
Geoff Langef7b0162014-09-04 13:29:23 -04002141
2142 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002143}
2144
Brandon Jones78b1acd2014-07-15 15:33:07 -07002145bool TextureD3D_3D::isValidLevel(int level) const
2146{
2147 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2148}
2149
2150bool TextureD3D_3D::isLevelComplete(int level) const
2151{
2152 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2153
2154 if (isImmutable())
2155 {
2156 return true;
2157 }
2158
2159 GLsizei width = getBaseLevelWidth();
2160 GLsizei height = getBaseLevelHeight();
2161 GLsizei depth = getBaseLevelDepth();
2162
2163 if (width <= 0 || height <= 0 || depth <= 0)
2164 {
2165 return false;
2166 }
2167
2168 if (level == 0)
2169 {
2170 return true;
2171 }
2172
2173 ImageD3D *levelImage = mImageArray[level];
2174
2175 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2176 {
2177 return false;
2178 }
2179
2180 if (levelImage->getWidth() != std::max(1, width >> level))
2181 {
2182 return false;
2183 }
2184
2185 if (levelImage->getHeight() != std::max(1, height >> level))
2186 {
2187 return false;
2188 }
2189
2190 if (levelImage->getDepth() != std::max(1, depth >> level))
2191 {
2192 return false;
2193 }
2194
2195 return true;
2196}
2197
Jamie Madille76bdda2014-10-20 17:13:52 -04002198bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2199{
2200 return isLevelComplete(index.mipIndex);
2201}
2202
Geoff Langef7b0162014-09-04 13:29:23 -04002203gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002204{
2205 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2206 ASSERT(isLevelComplete(level));
2207
2208 if (mImageArray[level]->isDirty())
2209 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002210 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2211 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002212 gl::Error error = commitRegion(index, region);
2213 if (error.isError())
2214 {
2215 return error;
2216 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002217 }
Geoff Langef7b0162014-09-04 13:29:23 -04002218
2219 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002220}
2221
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002222void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002223{
2224 // If there currently is a corresponding storage texture image, it has these parameters
2225 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2226 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2227 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2228 const GLenum storageFormat = getBaseLevelInternalFormat();
2229
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002230 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002231
2232 if (mTexStorage)
2233 {
2234 const int storageLevels = mTexStorage->getLevelCount();
2235
2236 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002237 size.width != storageWidth ||
2238 size.height != storageHeight ||
2239 size.depth != storageDepth ||
Brandon Jones78b1acd2014-07-15 15:33:07 -07002240 internalformat != storageFormat) // Discard mismatched storage
2241 {
2242 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2243 {
2244 mImageArray[i]->markDirty();
2245 }
2246
2247 SafeDelete(mTexStorage);
2248 mDirtyImages = true;
2249 }
2250 }
2251}
2252
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002253gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2254{
2255 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2256 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2257}
Brandon Jones142ec422014-07-16 10:31:30 -07002258
Jamie Madillcb83dc12014-09-29 10:46:12 -04002259gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2260{
2261 // The "layer" here does not apply to 3D images. We use one Image per mip.
2262 return gl::ImageIndex::Make3D(mip);
2263}
2264
Jamie Madill710e5772014-10-20 17:13:53 -04002265bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2266{
2267 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2268 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2269}
2270
Jamie Madill93e13fb2014-11-06 15:27:25 -05002271TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002272 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002273{
2274 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2275 {
2276 mLayerCounts[level] = 0;
2277 mImageArray[level] = NULL;
2278 }
2279}
2280
2281TextureD3D_2DArray::~TextureD3D_2DArray()
2282{
Austin Kinross69822602014-08-12 15:51:37 -07002283 // Delete the Images before the TextureStorage.
2284 // Images might be relying on the TextureStorage for some of their data.
2285 // 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 -07002286 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002287 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002288}
2289
Geoff Langb4dedf32015-01-05 14:08:53 -05002290ImageD3D *TextureD3D_2DArray::getImage(int level, int layer) const
Brandon Jones142ec422014-07-16 10:31:30 -07002291{
2292 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002293 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2294 layer < mLayerCounts[level]);
2295 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002296}
2297
Geoff Langb4dedf32015-01-05 14:08:53 -05002298ImageD3D *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
Jamie Madillfeda4d22014-09-17 13:03:29 -04002299{
2300 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002301 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2302 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002303 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002304 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002305}
2306
Brandon Jones142ec422014-07-16 10:31:30 -07002307GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2308{
2309 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2310 return mLayerCounts[level];
2311}
2312
Brandon Jones142ec422014-07-16 10:31:30 -07002313GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2314{
2315 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2316}
2317
2318GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2319{
2320 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2321}
2322
Brandon Jones142ec422014-07-16 10:31:30 -07002323GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2324{
2325 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2326}
2327
2328bool TextureD3D_2DArray::isDepth(GLint level) const
2329{
Geoff Lang5d601382014-07-22 15:14:06 -04002330 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002331}
2332
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002333gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
2334 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002335{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002336 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2337
Geoff Lang5d601382014-07-22 15:14:06 -04002338 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2339
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002340 redefineImage(level, sizedInternalFormat, size);
Brandon Jones142ec422014-07-16 10:31:30 -07002341
Geoff Lang5d601382014-07-22 15:14:06 -04002342 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002343 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002344
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002345 for (int i = 0; i < size.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002346 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002347 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002348 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002349 gl::Error error = TextureD3D::setImage(index, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002350 if (error.isError())
2351 {
2352 return error;
2353 }
Brandon Jones142ec422014-07-16 10:31:30 -07002354 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002355
2356 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002357}
2358
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002359gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
2360 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002361{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002362 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2363
Geoff Lang5d601382014-07-22 15:14:06 -04002364 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002365 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002366
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002367 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002368 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002369 int layer = area.z + i;
2370 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2371
2372 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002373
Jamie Madillfeda4d22014-09-17 13:03:29 -04002374 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002375 gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002376 if (error.isError())
2377 {
2378 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002379 }
2380 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002381
2382 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002383}
2384
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002385gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
2386 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
2387{
2388 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2389
2390 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2391 redefineImage(level, internalFormat, size);
2392
2393 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2394 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1);
2395
2396 for (int i = 0; i < size.depth; i++)
2397 {
2398 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2399
2400 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2401 gl::Error error = TextureD3D::setCompressedImage(index, unpack, layerPixels);
2402 if (error.isError())
2403 {
2404 return error;
2405 }
2406 }
2407
2408 return gl::Error(GL_NO_ERROR);
2409}
2410
2411gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
2412 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002413{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002414 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2415
Geoff Lang5d601382014-07-22 15:14:06 -04002416 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002417 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002418
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002419 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002420 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002421 int layer = area.z + i;
2422 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Brandon Jones142ec422014-07-16 10:31:30 -07002423
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002424 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
2425
2426 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2427 gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, layerPixels);
Geoff Langb5348332014-09-02 13:16:34 -04002428 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002429 {
Geoff Langb5348332014-09-02 13:16:34 -04002430 return error;
2431 }
2432
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002433 error = commitRegion(index, layerArea);
Geoff Langb5348332014-09-02 13:16:34 -04002434 if (error.isError())
2435 {
2436 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002437 }
2438 }
Geoff Langb5348332014-09-02 13:16:34 -04002439
2440 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002441}
2442
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002443gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
2444 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002445{
2446 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002447 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002448}
2449
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002450gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
2451 const gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002452{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002453 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2454
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002455 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002456
Jamie Madille76bdda2014-10-20 17:13:52 -04002457 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002458 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002459 gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
2460 gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04002461 if (error.isError())
2462 {
2463 return error;
2464 }
2465
Brandon Jones142ec422014-07-16 10:31:30 -07002466 mDirtyImages = true;
2467 }
2468 else
2469 {
Geoff Langef7b0162014-09-04 13:29:23 -04002470 gl::Error error = ensureRenderTarget();
2471 if (error.isError())
2472 {
2473 return error;
2474 }
Brandon Jones142ec422014-07-16 10:31:30 -07002475
2476 if (isValidLevel(level))
2477 {
Geoff Langef7b0162014-09-04 13:29:23 -04002478 error = updateStorageLevel(level);
2479 if (error.isError())
2480 {
2481 return error;
2482 }
Brandon Jones142ec422014-07-16 10:31:30 -07002483
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002484 error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2485 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04002486 if (error.isError())
2487 {
2488 return error;
2489 }
Brandon Jones142ec422014-07-16 10:31:30 -07002490 }
2491 }
Geoff Langef7b0162014-09-04 13:29:23 -04002492 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002493}
2494
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002495gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002496{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002497 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2498
Brandon Jones142ec422014-07-16 10:31:30 -07002499 deleteImages();
2500
Geoff Lang8fed1f72015-01-09 11:09:33 -05002501 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
Brandon Jones142ec422014-07-16 10:31:30 -07002502 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002503 gl::Extents levelLayerSize(std::max(1, size.width >> level),
2504 std::max(1, size.height >> level),
2505 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002506
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002507 mLayerCounts[level] = (level < levels ? size.depth : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002508
2509 if (mLayerCounts[level] > 0)
2510 {
2511 // Create new images for this level
2512 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2513
2514 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2515 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002516 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002517 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true);
Brandon Jones142ec422014-07-16 10:31:30 -07002518 }
2519 }
2520 }
2521
Geoff Lang1f8532b2014-09-05 09:46:13 -04002522 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002523 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002524 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002525
2526 gl::Error error = setCompleteTexStorage(storage);
2527 if (error.isError())
2528 {
2529 SafeDelete(storage);
2530 return error;
2531 }
2532
2533 mImmutable = true;
2534
2535 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002536}
2537
Brandon Jones6053a522014-07-25 16:22:09 -07002538void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002539{
Brandon Jones6053a522014-07-25 16:22:09 -07002540 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002541}
2542
Brandon Jones6053a522014-07-25 16:22:09 -07002543void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002544{
Brandon Jones6053a522014-07-25 16:22:09 -07002545 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002546}
2547
Brandon Jones6053a522014-07-25 16:22:09 -07002548
Jamie Madill4aa79e12014-09-29 10:46:14 -04002549void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002550{
2551 int baseWidth = getBaseLevelWidth();
2552 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002553 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002554 GLenum baseFormat = getBaseLevelInternalFormat();
2555
2556 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2557 int levelCount = mipLevels();
2558 for (int level = 1; level < levelCount; level++)
2559 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002560 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
2561 std::max(baseHeight >> level, 1),
2562 baseDepth);
2563 redefineImage(level, baseFormat, levelLayerSize);
Brandon Jones142ec422014-07-16 10:31:30 -07002564 }
Brandon Jones142ec422014-07-16 10:31:30 -07002565}
2566
Jamie Madillac7579c2014-09-17 16:59:33 -04002567unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002568{
Geoff Langef7b0162014-09-04 13:29:23 -04002569 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002570}
2571
Geoff Langc2e75af2015-01-05 14:26:24 -05002572gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTargetD3D **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002573{
2574 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002575 gl::Error error = ensureRenderTarget();
2576 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002577 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002578 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002579 }
2580
Geoff Langef7b0162014-09-04 13:29:23 -04002581 error = updateStorageLevel(index.mipIndex);
2582 if (error.isError())
2583 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002584 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002585 }
2586
Geoff Lang64f23f62014-09-10 14:40:12 -04002587 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002588}
2589
Geoff Langef7b0162014-09-04 13:29:23 -04002590gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002591{
2592 // Only initialize the first time this texture is used as a render target or shader resource
2593 if (mTexStorage)
2594 {
Geoff Langef7b0162014-09-04 13:29:23 -04002595 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002596 }
2597
2598 // do not attempt to create storage for nonexistant data
2599 if (!isLevelComplete(0))
2600 {
Geoff Langef7b0162014-09-04 13:29:23 -04002601 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002602 }
2603
2604 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2605
Geoff Langef7b0162014-09-04 13:29:23 -04002606 TextureStorage *storage = NULL;
2607 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2608 if (error.isError())
2609 {
2610 return error;
2611 }
2612
2613 error = setCompleteTexStorage(storage);
2614 if (error.isError())
2615 {
2616 SafeDelete(storage);
2617 return error;
2618 }
2619
Brandon Jones142ec422014-07-16 10:31:30 -07002620 ASSERT(mTexStorage);
2621
2622 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002623 error = updateStorage();
2624 if (error.isError())
2625 {
2626 return error;
2627 }
2628
2629 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002630}
2631
Geoff Langef7b0162014-09-04 13:29:23 -04002632gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002633{
2634 GLsizei width = getBaseLevelWidth();
2635 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002636 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002637 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002638
2639 ASSERT(width > 0 && height > 0 && depth > 0);
2640
2641 // use existing storage level count, when previously specified by TexStorage*D
2642 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2643
Geoff Langef7b0162014-09-04 13:29:23 -04002644 // TODO(geofflang): Verify storage creation succeeds
2645 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2646
2647 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002648}
2649
Geoff Langef7b0162014-09-04 13:29:23 -04002650gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002651{
2652 SafeDelete(mTexStorage);
2653 mTexStorage = newCompleteTexStorage;
2654 mDirtyImages = true;
2655
2656 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2657 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002658
2659 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002660}
2661
Geoff Langef7b0162014-09-04 13:29:23 -04002662gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002663{
2664 ASSERT(mTexStorage != NULL);
2665 GLint storageLevels = mTexStorage->getLevelCount();
2666 for (int level = 0; level < storageLevels; level++)
2667 {
2668 if (isLevelComplete(level))
2669 {
Geoff Langef7b0162014-09-04 13:29:23 -04002670 gl::Error error = updateStorageLevel(level);
2671 if (error.isError())
2672 {
2673 return error;
2674 }
Brandon Jones142ec422014-07-16 10:31:30 -07002675 }
2676 }
Geoff Langef7b0162014-09-04 13:29:23 -04002677
2678 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002679}
2680
Brandon Jones142ec422014-07-16 10:31:30 -07002681bool TextureD3D_2DArray::isValidLevel(int level) const
2682{
2683 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2684}
2685
2686bool TextureD3D_2DArray::isLevelComplete(int level) const
2687{
2688 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2689
2690 if (isImmutable())
2691 {
2692 return true;
2693 }
2694
2695 GLsizei width = getBaseLevelWidth();
2696 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002697 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002698
2699 if (width <= 0 || height <= 0 || layers <= 0)
2700 {
2701 return false;
2702 }
2703
2704 if (level == 0)
2705 {
2706 return true;
2707 }
2708
2709 if (getInternalFormat(level) != getInternalFormat(0))
2710 {
2711 return false;
2712 }
2713
2714 if (getWidth(level) != std::max(1, width >> level))
2715 {
2716 return false;
2717 }
2718
2719 if (getHeight(level) != std::max(1, height >> level))
2720 {
2721 return false;
2722 }
2723
Jamie Madill3269bcb2014-09-30 16:33:52 -04002724 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002725 {
2726 return false;
2727 }
2728
2729 return true;
2730}
2731
Jamie Madille76bdda2014-10-20 17:13:52 -04002732bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2733{
2734 return isLevelComplete(index.mipIndex);
2735}
2736
Geoff Langef7b0162014-09-04 13:29:23 -04002737gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002738{
2739 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2740 ASSERT(isLevelComplete(level));
2741
2742 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2743 {
2744 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2745 if (mImageArray[level][layer]->isDirty())
2746 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002747 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2748 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002749 gl::Error error = commitRegion(index, region);
2750 if (error.isError())
2751 {
2752 return error;
2753 }
Brandon Jones142ec422014-07-16 10:31:30 -07002754 }
2755 }
Geoff Langef7b0162014-09-04 13:29:23 -04002756
2757 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002758}
2759
2760void TextureD3D_2DArray::deleteImages()
2761{
2762 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2763 {
2764 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2765 {
2766 delete mImageArray[level][layer];
2767 }
2768 delete[] mImageArray[level];
2769 mImageArray[level] = NULL;
2770 mLayerCounts[level] = 0;
2771 }
2772}
2773
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002774void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002775{
2776 // If there currently is a corresponding storage texture image, it has these parameters
2777 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2778 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002779 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002780 const GLenum storageFormat = getBaseLevelInternalFormat();
2781
2782 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2783 {
2784 delete mImageArray[level][layer];
2785 }
2786 delete[] mImageArray[level];
2787 mImageArray[level] = NULL;
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002788 mLayerCounts[level] = size.depth;
Brandon Jones142ec422014-07-16 10:31:30 -07002789
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002790 if (size.depth > 0)
Brandon Jones142ec422014-07-16 10:31:30 -07002791 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002792 mImageArray[level] = new ImageD3D*[size.depth]();
Brandon Jones142ec422014-07-16 10:31:30 -07002793
2794 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2795 {
Geoff Langb4dedf32015-01-05 14:08:53 -05002796 mImageArray[level][layer] = mRenderer->createImage();
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002797 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
2798 gl::Extents(size.width, size.height, 1), false);
Brandon Jones142ec422014-07-16 10:31:30 -07002799 }
2800 }
2801
2802 if (mTexStorage)
2803 {
2804 const int storageLevels = mTexStorage->getLevelCount();
2805
2806 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002807 size.width != storageWidth ||
2808 size.height != storageHeight ||
2809 size.depth != storageDepth ||
Brandon Jones142ec422014-07-16 10:31:30 -07002810 internalformat != storageFormat) // Discard mismatched storage
2811 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08002812 for (int dirtyLevel = 0; dirtyLevel < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; dirtyLevel++)
Brandon Jones142ec422014-07-16 10:31:30 -07002813 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08002814 for (int dirtyLayer = 0; dirtyLayer < mLayerCounts[dirtyLevel]; dirtyLayer++)
Brandon Jones142ec422014-07-16 10:31:30 -07002815 {
Austin Kinrossc67e6e92015-01-21 16:01:07 -08002816 mImageArray[dirtyLevel][dirtyLayer]->markDirty();
Brandon Jones142ec422014-07-16 10:31:30 -07002817 }
2818 }
2819
2820 delete mTexStorage;
2821 mTexStorage = NULL;
2822 mDirtyImages = true;
2823 }
2824 }
2825}
2826
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002827gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2828{
2829 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2830}
2831
Jamie Madillcb83dc12014-09-29 10:46:12 -04002832gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2833{
2834 return gl::ImageIndex::Make2DArray(mip, layer);
2835}
2836
Jamie Madill710e5772014-10-20 17:13:53 -04002837bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2838{
2839 // Check for having a storage and the right type of index
2840 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2841 {
2842 return false;
2843 }
2844
2845 // Check the mip index
2846 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2847 {
2848 return false;
2849 }
2850
2851 // Check the layer index
2852 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2853}
2854
Brandon Jones78b1acd2014-07-15 15:33:07 -07002855}