blob: 12daaa7a9aa043fbd5291adfe31694c3a133c785 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Jamie Madillfb0580a2014-11-27 14:03:52 -05009#include "libANGLE/renderer/d3d/TextureD3D.h"
10
11#include "common/mathutil.h"
12#include "common/utilities.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Buffer.h"
14#include "libANGLE/Framebuffer.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050015#include "libANGLE/Surface.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Texture.h"
17#include "libANGLE/formatutils.h"
18#include "libANGLE/renderer/BufferImpl.h"
19#include "libANGLE/renderer/RenderTarget.h"
20#include "libANGLE/renderer/d3d/BufferD3D.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050021#include "libANGLE/renderer/d3d/ImageD3D.h"
22#include "libANGLE/renderer/d3d/RendererD3D.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050023#include "libANGLE/renderer/d3d/SurfaceD3D.h"
24#include "libANGLE/renderer/d3d/TextureStorage.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
32gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut)
33{
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 {
55 *pointerOut = static_cast<const uint8_t *>(pixels);
56 }
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{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700102 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700103 return (baseImage ? baseImage->getWidth() : 0);
104}
105
106GLint TextureD3D::getBaseLevelHeight() const
107{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700108 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700109 return (baseImage ? baseImage->getHeight() : 0);
110}
111
112GLint TextureD3D::getBaseLevelDepth() const
113{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700114 const Image *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{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700123 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
125}
126
Jamie Madillec6de4e2014-10-20 10:59:56 -0400127bool TextureD3D::shouldUseSetData(const Image *image) const
128{
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
Jamie Madillba6bc952014-10-06 10:56:22 -0400147gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
Jamie Madillba6bc952014-10-06 10:56:22 -0400149 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400150 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400151
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152 // No-op
153 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
154 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400155 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700156 }
157
158 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
159 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill9aca0592014-10-06 16:26:59 -0400160 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400161 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
162 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400164 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 }
166
167 if (pixelData != NULL)
168 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400169 gl::Error error(GL_NO_ERROR);
170
Jamie Madillec6de4e2014-10-20 10:59:56 -0400171 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400172 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400173 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400174 }
175 else
176 {
177 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
178 }
179
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400180 if (error.isError())
181 {
182 return error;
183 }
184
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700185 mDirtyImages = true;
186 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400187
188 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700189}
190
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400191gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
192 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700193{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400195 const uint8_t *pixelData = NULL;
196 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
197 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400199 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700200 }
201
202 if (pixelData != NULL)
203 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400204 Image *image = getImage(index);
205 ASSERT(image);
206
Jamie Madill9aca0592014-10-06 16:26:59 -0400207 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400208 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400210 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400211 }
212
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400213 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
214 type, pixelData);
215 if (error.isError())
216 {
217 return error;
218 }
219
Jamie Madille6b6da02014-10-02 11:03:14 -0400220 error = commitRegion(index, region);
221 if (error.isError())
222 {
223 return error;
224 }
225
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700226 mDirtyImages = true;
227 }
228
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400229 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700230}
231
Jamie Madillc751d1e2014-10-21 17:46:29 -0400232gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700233{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400234 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
235 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
236 const uint8_t *pixelData = NULL;
237 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
238 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700239 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400240 return error;
241 }
242
243 if (pixelData != NULL)
244 {
245 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400246 if (error.isError())
247 {
248 return error;
249 }
250
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700251 mDirtyImages = true;
252 }
Geoff Langb5348332014-09-02 13:16:34 -0400253
254 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700255}
256
Geoff Langb5348332014-09-02 13:16:34 -0400257gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400258 GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700259{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400260 const uint8_t *pixelData = NULL;
261 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
262 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700263 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400264 return error;
265 }
266
267 if (pixelData != NULL)
268 {
269 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400270 if (error.isError())
271 {
272 return error;
273 }
274
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700275 mDirtyImages = true;
276 }
277
Geoff Langb5348332014-09-02 13:16:34 -0400278 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700279}
280
281bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
282{
283 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
284}
285
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400286gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
287 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700288{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400289 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700290 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
291 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400292 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700293 }
294
295 // In order to perform the fast copy through the shader, we must have the right format, and be able
296 // to create a render target.
297 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
298
Jacek Cabana5521de2014-10-01 17:23:46 +0200299 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700300
Geoff Langae5122c2014-08-27 14:08:43 -0400301 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
302 if (error.isError())
303 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400304 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400305 }
306
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400307 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700308}
309
310GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
311{
312 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
313 {
314 // Maximum number of levels
315 return gl::log2(std::max(std::max(width, height), depth)) + 1;
316 }
317 else
318 {
319 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
320 return 1;
321 }
322}
323
324int TextureD3D::mipLevels() const
325{
326 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
327}
328
Jamie Madill98553e32014-09-30 16:33:50 -0400329TextureStorage *TextureD3D::getStorage()
330{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400331 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400332 return mTexStorage;
333}
334
Jamie Madill3269bcb2014-09-30 16:33:52 -0400335Image *TextureD3D::getBaseLevelImage() const
336{
337 return getImage(getImageIndex(0, 0));
338}
339
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400340gl::Error TextureD3D::generateMipmaps()
Jamie Madill4aa79e12014-09-29 10:46:14 -0400341{
Jamie Madill9aca0592014-10-06 16:26:59 -0400342 GLint mipCount = mipLevels();
343
344 if (mipCount == 1)
345 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400346 return gl::Error(GL_NO_ERROR); // no-op
Jamie Madill9aca0592014-10-06 16:26:59 -0400347 }
348
349 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400350 initMipmapsImages();
351
352 // We know that all layers have the same dimension, for the texture to be complete
353 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400354
Jamie Madill9aca0592014-10-06 16:26:59 -0400355 // When making mipmaps with the setData workaround enabled, the texture storage has
356 // the image data already. For non-render-target storage, we have to pull it out into
357 // an image layer.
358 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
359 {
360 if (!mTexStorage->isRenderTarget())
361 {
362 // Copy from the storage mip 0 to Image mip 0
363 for (GLint layer = 0; layer < layerCount; ++layer)
364 {
365 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400366
Jamie Madill9aca0592014-10-06 16:26:59 -0400367 Image *image = getImage(srcIndex);
368 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400369 gl::Error error = image->copy(0, 0, 0, area, srcIndex, mTexStorage);
370 if (error.isError())
371 {
372 return error;
373 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400374 }
375 }
376 else
377 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400378 gl::Error error = updateStorage();
379 if (error.isError())
380 {
381 return error;
382 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400383 }
384 }
385
386 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400387
388 for (GLint layer = 0; layer < layerCount; ++layer)
389 {
390 for (GLint mip = 1; mip < mipCount; ++mip)
391 {
392 ASSERT(getLayerCount(mip) == layerCount);
393
394 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
395 gl::ImageIndex destIndex = getImageIndex(mip, layer);
396
397 if (renderableStorage)
398 {
399 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400400 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
401 if (error.isError())
402 {
403 return error;
404 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400405 }
406 else
407 {
408 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400409 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
410 if (error.isError())
411 {
412 return error;
413 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400414 }
415 }
416 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400417
418 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400419}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700420
Jamie Madill135570a2014-09-30 16:33:51 -0400421bool TextureD3D::isBaseImageZeroSize() const
422{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400423 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400424
425 if (!baseImage || baseImage->getWidth() <= 0)
426 {
427 return true;
428 }
429
430 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
431 {
432 return true;
433 }
434
435 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
436 {
437 return true;
438 }
439
440 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
441 {
442 return true;
443 }
444
445 return false;
446}
447
Geoff Langef7b0162014-09-04 13:29:23 -0400448gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400449{
Geoff Langef7b0162014-09-04 13:29:23 -0400450 gl::Error error = initializeStorage(true);
451 if (error.isError())
452 {
453 return error;
454 }
Jamie Madill135570a2014-09-30 16:33:51 -0400455
456 if (!isBaseImageZeroSize())
457 {
458 ASSERT(mTexStorage);
459 if (!mTexStorage->isRenderTarget())
460 {
Geoff Langef7b0162014-09-04 13:29:23 -0400461 TextureStorage *newRenderTargetStorage = NULL;
462 error = createCompleteStorage(true, &newRenderTargetStorage);
463 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400464 {
Geoff Langef7b0162014-09-04 13:29:23 -0400465 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400466 }
467
Geoff Langef7b0162014-09-04 13:29:23 -0400468 error = mTexStorage->copyToStorage(newRenderTargetStorage);
469 if (error.isError())
470 {
471 SafeDelete(newRenderTargetStorage);
472 return error;
473 }
474
475 error = setCompleteTexStorage(newRenderTargetStorage);
476 if (error.isError())
477 {
478 SafeDelete(newRenderTargetStorage);
479 return error;
480 }
Jamie Madill135570a2014-09-30 16:33:51 -0400481 }
482 }
483
Geoff Langef7b0162014-09-04 13:29:23 -0400484 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400485}
486
Jamie Madille76bdda2014-10-20 17:13:52 -0400487bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
488{
Jamie Madill30d6c252014-11-13 10:03:33 -0500489 Image *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400490 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
491 return (image->isRenderableFormat() && levelsComplete);
492}
493
Jamie Madill710e5772014-10-20 17:13:53 -0400494gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
495{
496 if (mTexStorage)
497 {
498 ASSERT(isValidIndex(index));
499 Image *image = getImage(index);
500 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
501 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
502 if (error.isError())
503 {
504 return error;
505 }
506
507 image->markClean();
508 }
509
510 return gl::Error(GL_NO_ERROR);
511}
512
Jamie Madill93e13fb2014-11-06 15:27:25 -0500513TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400514 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700515{
516 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
517 {
518 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
519 }
520}
521
522TextureD3D_2D::~TextureD3D_2D()
523{
Austin Kinross69822602014-08-12 15:51:37 -0700524 // Delete the Images before the TextureStorage.
525 // Images might be relying on the TextureStorage for some of their data.
526 // 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 -0700527 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
528 {
529 delete mImageArray[i];
530 }
Austin Kinross69822602014-08-12 15:51:37 -0700531
532 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700533}
534
Brandon Jonescef06ff2014-08-05 13:27:48 -0700535Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536{
537 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700538 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700539 return mImageArray[level];
540}
541
Jamie Madillfeda4d22014-09-17 13:03:29 -0400542Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
543{
544 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400545 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400546 ASSERT(index.type == GL_TEXTURE_2D);
547 return mImageArray[index.mipIndex];
548}
549
Brandon Jonescef06ff2014-08-05 13:27:48 -0700550GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700552 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
553 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700554}
555
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700556GLsizei TextureD3D_2D::getWidth(GLint level) const
557{
558 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
559 return mImageArray[level]->getWidth();
560 else
561 return 0;
562}
563
564GLsizei TextureD3D_2D::getHeight(GLint level) const
565{
566 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
567 return mImageArray[level]->getHeight();
568 else
569 return 0;
570}
571
572GLenum TextureD3D_2D::getInternalFormat(GLint level) const
573{
574 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
575 return mImageArray[level]->getInternalFormat();
576 else
577 return GL_NONE;
578}
579
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700580bool TextureD3D_2D::isDepth(GLint level) const
581{
Geoff Lang5d601382014-07-22 15:14:06 -0400582 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583}
584
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400585gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
586 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
587 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700588{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700589 ASSERT(target == GL_TEXTURE_2D && depth == 1);
590
Geoff Lang5d601382014-07-22 15:14:06 -0400591 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
592
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700593 bool fastUnpacked = false;
594
Brandon Jonescef06ff2014-08-05 13:27:48 -0700595 redefineImage(level, sizedInternalFormat, width, height);
596
Jamie Madillba6bc952014-10-06 10:56:22 -0400597 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
598
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599 // Attempt a fast gpu copy of the pixel data to the surface
600 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
601 {
602 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400603 RenderTarget *destRenderTarget = NULL;
604 gl::Error error = getRenderTarget(index, &destRenderTarget);
605 if (error.isError())
606 {
607 return error;
608 }
609
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
611
Geoff Lang64f23f62014-09-10 14:40:12 -0400612 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
613 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400615 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400617
618 // Ensure we don't overwrite our newly initialized data
619 mImageArray[level]->markClean();
620
621 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622 }
623
624 if (!fastUnpacked)
625 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400626 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400627 if (error.isError())
628 {
629 return error;
630 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400632
633 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634}
635
Geoff Langb5348332014-09-02 13:16:34 -0400636gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
637 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400638 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700640 ASSERT(target == GL_TEXTURE_2D && depth == 1);
641
642 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
643 redefineImage(level, format, width, height);
644
Jamie Madillc751d1e2014-10-21 17:46:29 -0400645 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700646}
647
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400648gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
649 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
650 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700652 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
653
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654 bool fastUnpacked = false;
655
Jamie Madillac7579c2014-09-17 16:59:33 -0400656 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400657 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700658 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
659 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400660 RenderTarget *renderTarget = NULL;
661 gl::Error error = getRenderTarget(index, &renderTarget);
662 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400664 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400666
667 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
668 if (error.isError())
669 {
670 return error;
671 }
672
673 // Ensure we don't overwrite our newly initialized data
674 mImageArray[level]->markClean();
675
676 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677 }
678
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400679 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700680 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400681 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
682 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400684
685 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686}
687
Geoff Langb5348332014-09-02 13:16:34 -0400688gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
689 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400690 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700692 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
693
Jamie Madillc751d1e2014-10-21 17:46:29 -0400694 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -0400695 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700696 {
Geoff Langb5348332014-09-02 13:16:34 -0400697 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700698 }
Geoff Langb5348332014-09-02 13:16:34 -0400699
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400700 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
701 gl::Box region(xoffset, yoffset, 0, width, height, 1);
702 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700703}
704
Geoff Langef7b0162014-09-04 13:29:23 -0400705gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
706 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700707{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700708 ASSERT(target == GL_TEXTURE_2D);
709
710 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
711 redefineImage(level, sizedInternalFormat, width, height);
712
Jamie Madill82bf0c52014-10-03 11:50:53 -0400713 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400714 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400715
Jamie Madille76bdda2014-10-20 17:13:52 -0400716 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700717 {
Geoff Langef7b0162014-09-04 13:29:23 -0400718 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
719 if (error.isError())
720 {
721 return error;
722 }
723
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700724 mDirtyImages = true;
725 }
726 else
727 {
Geoff Langef7b0162014-09-04 13:29:23 -0400728 gl::Error error = ensureRenderTarget();
729 if (error.isError())
730 {
731 return error;
732 }
733
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700734 mImageArray[level]->markClean();
735
736 if (width != 0 && height != 0 && isValidLevel(level))
737 {
Geoff Langef7b0162014-09-04 13:29:23 -0400738 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
739 if (error.isError())
740 {
741 return error;
742 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700743 }
744 }
Geoff Langef7b0162014-09-04 13:29:23 -0400745
746 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700747}
748
Geoff Langef7b0162014-09-04 13:29:23 -0400749gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
750 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700751{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700752 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
753
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700754 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
755 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700756
Jamie Madill82bf0c52014-10-03 11:50:53 -0400757 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400758 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400759
Jamie Madille76bdda2014-10-20 17:13:52 -0400760 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700761 {
Geoff Langef7b0162014-09-04 13:29:23 -0400762 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
763 if (error.isError())
764 {
765 return error;
766 }
767
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700768 mDirtyImages = true;
769 }
770 else
771 {
Geoff Langef7b0162014-09-04 13:29:23 -0400772 gl::Error error = ensureRenderTarget();
773 if (error.isError())
774 {
775 return error;
776 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700777
778 if (isValidLevel(level))
779 {
Geoff Langef7b0162014-09-04 13:29:23 -0400780 error = updateStorageLevel(level);
781 if (error.isError())
782 {
783 return error;
784 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785
Geoff Langef7b0162014-09-04 13:29:23 -0400786 error = mRenderer->copyImage2D(source, sourceRect,
787 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
788 xoffset, yoffset, mTexStorage, level);
789 if (error.isError())
790 {
791 return error;
792 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793 }
794 }
Geoff Langef7b0162014-09-04 13:29:23 -0400795
796 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700797}
798
Geoff Lang1f8532b2014-09-05 09:46:13 -0400799gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700800{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700801 ASSERT(target == GL_TEXTURE_2D && depth == 1);
802
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700803 for (int level = 0; level < levels; level++)
804 {
805 GLsizei levelWidth = std::max(1, width >> level);
806 GLsizei levelHeight = std::max(1, height >> level);
Austin Kinross049743a2014-12-23 13:05:11 -0800807 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700808 }
809
810 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
811 {
Austin Kinross049743a2014-12-23 13:05:11 -0800812 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813 }
814
Geoff Lang1f8532b2014-09-05 09:46:13 -0400815 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400816 bool renderTarget = IsRenderTargetUsage(mUsage);
817 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400818
819 gl::Error error = setCompleteTexStorage(storage);
820 if (error.isError())
821 {
822 SafeDelete(storage);
823 return error;
824 }
825
826 mImmutable = true;
827
828 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700829}
830
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700831void TextureD3D_2D::bindTexImage(egl::Surface *surface)
832{
833 GLenum internalformat = surface->getFormat();
834
Austin Kinross049743a2014-12-23 13:05:11 -0800835 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700836
837 if (mTexStorage)
838 {
839 SafeDelete(mTexStorage);
840 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400841
Jamie Madillfb0580a2014-11-27 14:03:52 -0500842 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
843 ASSERT(surfaceD3D);
844
845 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700846
847 mDirtyImages = true;
848}
849
850void TextureD3D_2D::releaseTexImage()
851{
852 if (mTexStorage)
853 {
854 SafeDelete(mTexStorage);
855 }
856
857 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
858 {
Austin Kinross049743a2014-12-23 13:05:11 -0800859 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700860 }
861}
862
Jamie Madill4aa79e12014-09-29 10:46:14 -0400863void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700865 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700867 for (int level = 1; level < levelCount; level++)
868 {
869 redefineImage(level, getBaseLevelInternalFormat(),
870 std::max(getBaseLevelWidth() >> level, 1),
871 std::max(getBaseLevelHeight() >> level, 1));
872 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700873}
874
Jamie Madillac7579c2014-09-17 16:59:33 -0400875unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700876{
Jamie Madillac7579c2014-09-17 16:59:33 -0400877 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400878 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700879}
880
Geoff Lang64f23f62014-09-10 14:40:12 -0400881gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882{
Jamie Madillac7579c2014-09-17 16:59:33 -0400883 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700884
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700885 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400886 gl::Error error = ensureRenderTarget();
887 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700888 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400889 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700890 }
891
Geoff Langef7b0162014-09-04 13:29:23 -0400892 error = updateStorageLevel(index.mipIndex);
893 if (error.isError())
894 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400895 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400896 }
897
Geoff Lang64f23f62014-09-10 14:40:12 -0400898 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700899}
900
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700901bool TextureD3D_2D::isValidLevel(int level) const
902{
903 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
904}
905
906bool TextureD3D_2D::isLevelComplete(int level) const
907{
908 if (isImmutable())
909 {
910 return true;
911 }
912
Brandon Jones78b1acd2014-07-15 15:33:07 -0700913 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700914
915 GLsizei width = baseImage->getWidth();
916 GLsizei height = baseImage->getHeight();
917
918 if (width <= 0 || height <= 0)
919 {
920 return false;
921 }
922
923 // The base image level is complete if the width and height are positive
924 if (level == 0)
925 {
926 return true;
927 }
928
929 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700930 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700931
932 if (image->getInternalFormat() != baseImage->getInternalFormat())
933 {
934 return false;
935 }
936
937 if (image->getWidth() != std::max(1, width >> level))
938 {
939 return false;
940 }
941
942 if (image->getHeight() != std::max(1, height >> level))
943 {
944 return false;
945 }
946
947 return true;
948}
949
Jamie Madille76bdda2014-10-20 17:13:52 -0400950bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
951{
952 return isLevelComplete(index.mipIndex);
953}
954
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700955// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400956gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700957{
958 // Only initialize the first time this texture is used as a render target or shader resource
959 if (mTexStorage)
960 {
Geoff Langef7b0162014-09-04 13:29:23 -0400961 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700962 }
963
964 // do not attempt to create storage for nonexistant data
965 if (!isLevelComplete(0))
966 {
Geoff Langef7b0162014-09-04 13:29:23 -0400967 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700968 }
969
970 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
971
Geoff Langef7b0162014-09-04 13:29:23 -0400972 TextureStorage *storage = NULL;
973 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
974 if (error.isError())
975 {
976 return error;
977 }
978
979 error = setCompleteTexStorage(storage);
980 if (error.isError())
981 {
982 SafeDelete(storage);
983 return error;
984 }
985
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700986 ASSERT(mTexStorage);
987
988 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400989 error = updateStorage();
990 if (error.isError())
991 {
992 return error;
993 }
994
995 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700996}
997
Geoff Langef7b0162014-09-04 13:29:23 -0400998gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700999{
1000 GLsizei width = getBaseLevelWidth();
1001 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001002 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001003
1004 ASSERT(width > 0 && height > 0);
1005
1006 // use existing storage level count, when previously specified by TexStorage*D
1007 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1008
Geoff Langef7b0162014-09-04 13:29:23 -04001009 // TODO(geofflang): Determine if the texture creation succeeded
1010 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
1011
1012 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001013}
1014
Geoff Langef7b0162014-09-04 13:29:23 -04001015gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001016{
Geoff Langef7b0162014-09-04 13:29:23 -04001017 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001018 {
Geoff Langef7b0162014-09-04 13:29:23 -04001019 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001020 {
Geoff Langef7b0162014-09-04 13:29:23 -04001021 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1022 if (error.isError())
1023 {
1024 return error;
1025 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001026 }
1027 }
1028
Geoff Langef7b0162014-09-04 13:29:23 -04001029 SafeDelete(mTexStorage);
1030 mTexStorage = newCompleteTexStorage;
1031
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001032 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001033
1034 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001035}
1036
Geoff Langef7b0162014-09-04 13:29:23 -04001037gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001038{
1039 ASSERT(mTexStorage != NULL);
1040 GLint storageLevels = mTexStorage->getLevelCount();
1041 for (int level = 0; level < storageLevels; level++)
1042 {
1043 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1044 {
Geoff Langef7b0162014-09-04 13:29:23 -04001045 gl::Error error = updateStorageLevel(level);
1046 if (error.isError())
1047 {
1048 return error;
1049 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001050 }
1051 }
Geoff Langef7b0162014-09-04 13:29:23 -04001052
1053 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001054}
1055
Geoff Langef7b0162014-09-04 13:29:23 -04001056gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001057{
1058 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1059 ASSERT(isLevelComplete(level));
1060
1061 if (mImageArray[level]->isDirty())
1062 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001063 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1064 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001065 gl::Error error = commitRegion(index, region);
1066 if (error.isError())
1067 {
1068 return error;
1069 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001070 }
Geoff Langef7b0162014-09-04 13:29:23 -04001071
1072 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001073}
1074
1075void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1076{
1077 // If there currently is a corresponding storage texture image, it has these parameters
1078 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1079 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1080 const GLenum storageFormat = getBaseLevelInternalFormat();
1081
Austin Kinross049743a2014-12-23 13:05:11 -08001082 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, width, height, 1, false);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001083
1084 if (mTexStorage)
1085 {
1086 const int storageLevels = mTexStorage->getLevelCount();
1087
1088 if ((level >= storageLevels && storageLevels != 0) ||
1089 width != storageWidth ||
1090 height != storageHeight ||
1091 internalformat != storageFormat) // Discard mismatched storage
1092 {
1093 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1094 {
1095 mImageArray[i]->markDirty();
1096 }
1097
1098 SafeDelete(mTexStorage);
1099 mDirtyImages = true;
1100 }
1101 }
1102}
1103
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001104gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1105{
1106 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1107}
Brandon Jones0511e802014-07-14 16:27:26 -07001108
Jamie Madillcb83dc12014-09-29 10:46:12 -04001109gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1110{
1111 // "layer" does not apply to 2D Textures.
1112 return gl::ImageIndex::Make2D(mip);
1113}
1114
Jamie Madill710e5772014-10-20 17:13:53 -04001115bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1116{
1117 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1118 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1119}
1120
Jamie Madill93e13fb2014-11-06 15:27:25 -05001121TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001122 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001123{
1124 for (int i = 0; i < 6; i++)
1125 {
1126 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1127 {
1128 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1129 }
1130 }
1131}
1132
1133TextureD3D_Cube::~TextureD3D_Cube()
1134{
Austin Kinross69822602014-08-12 15:51:37 -07001135 // Delete the Images before the TextureStorage.
1136 // Images might be relying on the TextureStorage for some of their data.
1137 // 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 -07001138 for (int i = 0; i < 6; i++)
1139 {
1140 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1141 {
1142 SafeDelete(mImageArray[i][j]);
1143 }
1144 }
Austin Kinross69822602014-08-12 15:51:37 -07001145
1146 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001147}
1148
Brandon Jonescef06ff2014-08-05 13:27:48 -07001149Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001150{
1151 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001152 ASSERT(layer >= 0 && layer < 6);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001153 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001154}
1155
Jamie Madillfeda4d22014-09-17 13:03:29 -04001156Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1157{
1158 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001159 ASSERT(index.layerIndex >= 0 && index.layerIndex < 6);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001160 return mImageArray[index.layerIndex][index.mipIndex];
1161}
1162
Brandon Jonescef06ff2014-08-05 13:27:48 -07001163GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001164{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001165 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1166 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001167}
1168
Brandon Jonescef06ff2014-08-05 13:27:48 -07001169GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
1171 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001172 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001173 else
1174 return GL_NONE;
1175}
1176
Brandon Jonescef06ff2014-08-05 13:27:48 -07001177bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001178{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001179 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001180}
1181
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001182gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1183 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1184 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001185{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001186 ASSERT(depth == 1);
1187
Geoff Lang5d601382014-07-22 15:14:06 -04001188 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001189 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001190
Jamie Madillba6bc952014-10-06 10:56:22 -04001191 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001192
Jamie Madillba6bc952014-10-06 10:56:22 -04001193 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001194}
1195
Geoff Langb5348332014-09-02 13:16:34 -04001196gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1197 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001198 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001199{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001200 ASSERT(depth == 1);
1201
Brandon Jones0511e802014-07-14 16:27:26 -07001202 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001203 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1204
Brandon Jones0511e802014-07-14 16:27:26 -07001205 redefineImage(faceIndex, level, format, width, height);
1206
Jamie Madillc751d1e2014-10-21 17:46:29 -04001207 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001208}
1209
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001210gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1211 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1212 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001213{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001214 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001215 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001216 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001217}
1218
Geoff Langb5348332014-09-02 13:16:34 -04001219gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1220 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001221 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001222{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001223 ASSERT(depth == 1 && zoffset == 0);
1224
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001225 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001226
Jamie Madillc751d1e2014-10-21 17:46:29 -04001227 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -04001228 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001229 {
Geoff Langb5348332014-09-02 13:16:34 -04001230 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001231 }
Geoff Langb5348332014-09-02 13:16:34 -04001232
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001233 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1234 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001235}
1236
Geoff Langef7b0162014-09-04 13:29:23 -04001237gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1238 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001239{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001240 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001241 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1242
Brandon Jones0511e802014-07-14 16:27:26 -07001243 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1244
Jamie Madill82bf0c52014-10-03 11:50:53 -04001245 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001246 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001247
Jamie Madille76bdda2014-10-20 17:13:52 -04001248 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001249 {
Geoff Langef7b0162014-09-04 13:29:23 -04001250 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1251 if (error.isError())
1252 {
1253 return error;
1254 }
1255
Brandon Jones0511e802014-07-14 16:27:26 -07001256 mDirtyImages = true;
1257 }
1258 else
1259 {
Geoff Langef7b0162014-09-04 13:29:23 -04001260 gl::Error error = ensureRenderTarget();
1261 if (error.isError())
1262 {
1263 return error;
1264 }
1265
Brandon Jones0511e802014-07-14 16:27:26 -07001266 mImageArray[faceIndex][level]->markClean();
1267
1268 ASSERT(width == height);
1269
1270 if (width > 0 && isValidFaceLevel(faceIndex, level))
1271 {
Geoff Langef7b0162014-09-04 13:29:23 -04001272 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1273 if (error.isError())
1274 {
1275 return error;
1276 }
Brandon Jones0511e802014-07-14 16:27:26 -07001277 }
1278 }
Geoff Langef7b0162014-09-04 13:29:23 -04001279
1280 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001281}
1282
Geoff Langef7b0162014-09-04 13:29:23 -04001283gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1284 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001285{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001286 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001287
Jamie Madill82bf0c52014-10-03 11:50:53 -04001288 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001289 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001290
Jamie Madille76bdda2014-10-20 17:13:52 -04001291 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001292 {
Geoff Langef7b0162014-09-04 13:29:23 -04001293 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1294 if (error.isError())
1295 {
1296 return error;
1297 }
1298
Brandon Jones0511e802014-07-14 16:27:26 -07001299 mDirtyImages = true;
1300 }
1301 else
1302 {
Geoff Langef7b0162014-09-04 13:29:23 -04001303 gl::Error error = ensureRenderTarget();
1304 if (error.isError())
1305 {
1306 return error;
1307 }
Brandon Jones0511e802014-07-14 16:27:26 -07001308
1309 if (isValidFaceLevel(faceIndex, level))
1310 {
Geoff Langef7b0162014-09-04 13:29:23 -04001311 error = updateStorageFaceLevel(faceIndex, level);
1312 if (error.isError())
1313 {
1314 return error;
1315 }
Brandon Jones0511e802014-07-14 16:27:26 -07001316
Geoff Langef7b0162014-09-04 13:29:23 -04001317 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1318 xoffset, yoffset, mTexStorage, target, level);
1319 if (error.isError())
1320 {
1321 return error;
1322 }
Brandon Jones0511e802014-07-14 16:27:26 -07001323 }
1324 }
Geoff Langef7b0162014-09-04 13:29:23 -04001325
1326 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001327}
1328
Geoff Lang1f8532b2014-09-05 09:46:13 -04001329gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001330{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001331 ASSERT(width == height);
1332 ASSERT(depth == 1);
1333
Brandon Jones0511e802014-07-14 16:27:26 -07001334 for (int level = 0; level < levels; level++)
1335 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001336 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001337 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1338 {
Austin Kinross049743a2014-12-23 13:05:11 -08001339 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
Brandon Jones0511e802014-07-14 16:27:26 -07001340 }
1341 }
1342
1343 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1344 {
1345 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1346 {
Austin Kinross049743a2014-12-23 13:05:11 -08001347 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
Brandon Jones0511e802014-07-14 16:27:26 -07001348 }
1349 }
1350
Geoff Lang1f8532b2014-09-05 09:46:13 -04001351 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001352 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001353 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001354
1355 gl::Error error = setCompleteTexStorage(storage);
1356 if (error.isError())
1357 {
1358 SafeDelete(storage);
1359 return error;
1360 }
1361
1362 mImmutable = true;
1363
1364 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001365}
1366
Brandon Jones0511e802014-07-14 16:27:26 -07001367// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1368bool TextureD3D_Cube::isCubeComplete() const
1369{
1370 int baseWidth = getBaseLevelWidth();
1371 int baseHeight = getBaseLevelHeight();
1372 GLenum baseFormat = getBaseLevelInternalFormat();
1373
1374 if (baseWidth <= 0 || baseWidth != baseHeight)
1375 {
1376 return false;
1377 }
1378
1379 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1380 {
1381 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1382
1383 if (faceBaseImage.getWidth() != baseWidth ||
1384 faceBaseImage.getHeight() != baseHeight ||
1385 faceBaseImage.getInternalFormat() != baseFormat )
1386 {
1387 return false;
1388 }
1389 }
1390
1391 return true;
1392}
1393
Brandon Jones6053a522014-07-25 16:22:09 -07001394void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1395{
1396 UNREACHABLE();
1397}
1398
1399void TextureD3D_Cube::releaseTexImage()
1400{
1401 UNREACHABLE();
1402}
1403
1404
Jamie Madill4aa79e12014-09-29 10:46:14 -04001405void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001406{
1407 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1408 int levelCount = mipLevels();
1409 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1410 {
1411 for (int level = 1; level < levelCount; level++)
1412 {
1413 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1414 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1415 }
1416 }
Brandon Jones0511e802014-07-14 16:27:26 -07001417}
1418
Jamie Madillac7579c2014-09-17 16:59:33 -04001419unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001420{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001421 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001422}
1423
Geoff Lang64f23f62014-09-10 14:40:12 -04001424gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001425{
Jamie Madillac7579c2014-09-17 16:59:33 -04001426 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001427
1428 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001429 gl::Error error = ensureRenderTarget();
1430 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001431 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001432 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001433 }
1434
Geoff Langef7b0162014-09-04 13:29:23 -04001435 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1436 if (error.isError())
1437 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001438 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001439 }
1440
Geoff Lang64f23f62014-09-10 14:40:12 -04001441 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001442}
1443
Geoff Langef7b0162014-09-04 13:29:23 -04001444gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001445{
1446 // Only initialize the first time this texture is used as a render target or shader resource
1447 if (mTexStorage)
1448 {
Geoff Langef7b0162014-09-04 13:29:23 -04001449 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001450 }
1451
1452 // do not attempt to create storage for nonexistant data
1453 if (!isFaceLevelComplete(0, 0))
1454 {
Geoff Langef7b0162014-09-04 13:29:23 -04001455 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001456 }
1457
1458 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1459
Geoff Langef7b0162014-09-04 13:29:23 -04001460 TextureStorage *storage = NULL;
1461 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1462 if (error.isError())
1463 {
1464 return error;
1465 }
1466
1467 error = setCompleteTexStorage(storage);
1468 if (error.isError())
1469 {
1470 SafeDelete(storage);
1471 return error;
1472 }
1473
Brandon Jones0511e802014-07-14 16:27:26 -07001474 ASSERT(mTexStorage);
1475
1476 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001477 error = updateStorage();
1478 if (error.isError())
1479 {
1480 return error;
1481 }
1482
1483 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001484}
1485
Geoff Langef7b0162014-09-04 13:29:23 -04001486gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001487{
1488 GLsizei size = getBaseLevelWidth();
1489
1490 ASSERT(size > 0);
1491
1492 // use existing storage level count, when previously specified by TexStorage*D
1493 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1494
Geoff Langef7b0162014-09-04 13:29:23 -04001495 // TODO (geofflang): detect if storage creation succeeded
1496 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1497
1498 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001499}
1500
Geoff Langef7b0162014-09-04 13:29:23 -04001501gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001502{
Geoff Langef7b0162014-09-04 13:29:23 -04001503 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001504 {
1505 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1506 {
Geoff Langef7b0162014-09-04 13:29:23 -04001507 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001508 {
Geoff Langef7b0162014-09-04 13:29:23 -04001509 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1510 if (error.isError())
1511 {
1512 return error;
1513 }
Brandon Jones0511e802014-07-14 16:27:26 -07001514 }
1515 }
1516 }
1517
Geoff Langef7b0162014-09-04 13:29:23 -04001518 SafeDelete(mTexStorage);
1519 mTexStorage = newCompleteTexStorage;
1520
Brandon Jones0511e802014-07-14 16:27:26 -07001521 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001522 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001523}
1524
Geoff Langef7b0162014-09-04 13:29:23 -04001525gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001526{
1527 ASSERT(mTexStorage != NULL);
1528 GLint storageLevels = mTexStorage->getLevelCount();
1529 for (int face = 0; face < 6; face++)
1530 {
1531 for (int level = 0; level < storageLevels; level++)
1532 {
1533 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1534 {
Geoff Langef7b0162014-09-04 13:29:23 -04001535 gl::Error error = updateStorageFaceLevel(face, level);
1536 if (error.isError())
1537 {
1538 return error;
1539 }
Brandon Jones0511e802014-07-14 16:27:26 -07001540 }
1541 }
1542 }
Geoff Langef7b0162014-09-04 13:29:23 -04001543
1544 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001545}
1546
Brandon Jones0511e802014-07-14 16:27:26 -07001547bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1548{
1549 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1550}
1551
Brandon Jones0511e802014-07-14 16:27:26 -07001552bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1553{
1554 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1555
1556 if (isImmutable())
1557 {
1558 return true;
1559 }
1560
1561 int baseSize = getBaseLevelWidth();
1562
1563 if (baseSize <= 0)
1564 {
1565 return false;
1566 }
1567
1568 // "isCubeComplete" checks for base level completeness and we must call that
1569 // to determine if any face at level 0 is complete. We omit that check here
1570 // to avoid re-checking cube-completeness for every face at level 0.
1571 if (level == 0)
1572 {
1573 return true;
1574 }
1575
1576 // Check that non-zero levels are consistent with the base level.
1577 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1578
1579 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1580 {
1581 return false;
1582 }
1583
1584 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1585 {
1586 return false;
1587 }
1588
1589 return true;
1590}
1591
Jamie Madille76bdda2014-10-20 17:13:52 -04001592bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1593{
1594 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1595}
1596
Geoff Langef7b0162014-09-04 13:29:23 -04001597gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001598{
1599 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1600 ImageD3D *image = mImageArray[faceIndex][level];
1601
1602 if (image->isDirty())
1603 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001604 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1605 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1606 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001607 gl::Error error = commitRegion(index, region);
1608 if (error.isError())
1609 {
1610 return error;
1611 }
Brandon Jones0511e802014-07-14 16:27:26 -07001612 }
Geoff Langef7b0162014-09-04 13:29:23 -04001613
1614 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001615}
1616
1617void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1618{
1619 // If there currently is a corresponding storage texture image, it has these parameters
1620 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1621 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1622 const GLenum storageFormat = getBaseLevelInternalFormat();
1623
Austin Kinross049743a2014-12-23 13:05:11 -08001624 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001625
1626 if (mTexStorage)
1627 {
1628 const int storageLevels = mTexStorage->getLevelCount();
1629
1630 if ((level >= storageLevels && storageLevels != 0) ||
1631 width != storageWidth ||
1632 height != storageHeight ||
1633 internalformat != storageFormat) // Discard mismatched storage
1634 {
1635 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1636 {
1637 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1638 {
1639 mImageArray[faceIndex][level]->markDirty();
1640 }
1641 }
1642
1643 SafeDelete(mTexStorage);
1644
1645 mDirtyImages = true;
1646 }
1647 }
1648}
1649
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001650gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1651{
1652 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1653}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654
Jamie Madillcb83dc12014-09-29 10:46:12 -04001655gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1656{
1657 // The "layer" of the image index corresponds to the cube face
1658 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1659}
1660
Jamie Madill710e5772014-10-20 17:13:53 -04001661bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1662{
1663 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1664 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1665}
1666
Jamie Madill93e13fb2014-11-06 15:27:25 -05001667TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001668 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001669{
1670 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1671 {
1672 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1673 }
1674}
1675
1676TextureD3D_3D::~TextureD3D_3D()
1677{
Austin Kinross69822602014-08-12 15:51:37 -07001678 // Delete the Images before the TextureStorage.
1679 // Images might be relying on the TextureStorage for some of their data.
1680 // 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 -07001681 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1682 {
1683 delete mImageArray[i];
1684 }
Austin Kinross69822602014-08-12 15:51:37 -07001685
1686 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001687}
1688
Brandon Jonescef06ff2014-08-05 13:27:48 -07001689Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001690{
1691 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001692 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001693 return mImageArray[level];
1694}
1695
Jamie Madillfeda4d22014-09-17 13:03:29 -04001696Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1697{
1698 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001699 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001700 ASSERT(index.type == GL_TEXTURE_3D);
1701 return mImageArray[index.mipIndex];
1702}
1703
Brandon Jonescef06ff2014-08-05 13:27:48 -07001704GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001705{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001706 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1707 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001708}
1709
Brandon Jones78b1acd2014-07-15 15:33:07 -07001710GLsizei TextureD3D_3D::getWidth(GLint level) const
1711{
1712 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1713 return mImageArray[level]->getWidth();
1714 else
1715 return 0;
1716}
1717
1718GLsizei TextureD3D_3D::getHeight(GLint level) const
1719{
1720 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1721 return mImageArray[level]->getHeight();
1722 else
1723 return 0;
1724}
1725
1726GLsizei TextureD3D_3D::getDepth(GLint level) const
1727{
1728 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1729 return mImageArray[level]->getDepth();
1730 else
1731 return 0;
1732}
1733
1734GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1735{
1736 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1737 return mImageArray[level]->getInternalFormat();
1738 else
1739 return GL_NONE;
1740}
1741
1742bool TextureD3D_3D::isDepth(GLint level) const
1743{
Geoff Lang5d601382014-07-22 15:14:06 -04001744 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001745}
1746
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001747gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1748 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1749 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001750{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001751 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001752 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1753
Brandon Jones78b1acd2014-07-15 15:33:07 -07001754 redefineImage(level, sizedInternalFormat, width, height, depth);
1755
1756 bool fastUnpacked = false;
1757
Jamie Madillba6bc952014-10-06 10:56:22 -04001758 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1759
Brandon Jones78b1acd2014-07-15 15:33:07 -07001760 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1761 if (isFastUnpackable(unpack, sizedInternalFormat))
1762 {
1763 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001764 RenderTarget *destRenderTarget = NULL;
1765 gl::Error error = getRenderTarget(index, &destRenderTarget);
1766 if (error.isError())
1767 {
1768 return error;
1769 }
1770
Brandon Jones78b1acd2014-07-15 15:33:07 -07001771 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1772
Geoff Lang64f23f62014-09-10 14:40:12 -04001773 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1774 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001775 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001776 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001778
1779 // Ensure we don't overwrite our newly initialized data
1780 mImageArray[level]->markClean();
1781
1782 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001783 }
1784
1785 if (!fastUnpacked)
1786 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001787 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001788 if (error.isError())
1789 {
1790 return error;
1791 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001792 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001793
1794 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001795}
1796
Geoff Langb5348332014-09-02 13:16:34 -04001797gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1798 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001799 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001800{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001801 ASSERT(target == GL_TEXTURE_3D);
1802
Brandon Jones78b1acd2014-07-15 15:33:07 -07001803 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1804 redefineImage(level, format, width, height, depth);
1805
Jamie Madillc751d1e2014-10-21 17:46:29 -04001806 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001807}
1808
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001809gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1810 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1811 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001813 ASSERT(target == GL_TEXTURE_3D);
1814
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815 bool fastUnpacked = false;
1816
Jamie Madillac7579c2014-09-17 16:59:33 -04001817 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1818
Brandon Jones78b1acd2014-07-15 15:33:07 -07001819 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1820 if (isFastUnpackable(unpack, getInternalFormat(level)))
1821 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001822 RenderTarget *destRenderTarget = NULL;
1823 gl::Error error = getRenderTarget(index, &destRenderTarget);
1824 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001825 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001826 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001827 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001828
1829 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1830 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1831 if (error.isError())
1832 {
1833 return error;
1834 }
1835
1836 // Ensure we don't overwrite our newly initialized data
1837 mImageArray[level]->markClean();
1838
1839 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001840 }
1841
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001842 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001843 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001844 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1845 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001846 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001847
1848 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849}
1850
Geoff Langb5348332014-09-02 13:16:34 -04001851gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1852 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001853 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001855 ASSERT(target == GL_TEXTURE_3D);
1856
Geoff Langb5348332014-09-02 13:16:34 -04001857 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001858 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001859 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001860 {
Geoff Langb5348332014-09-02 13:16:34 -04001861 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001862 }
Geoff Langb5348332014-09-02 13:16:34 -04001863
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001864 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1865 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1866 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001867}
1868
Geoff Langef7b0162014-09-04 13:29:23 -04001869gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1870 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001871{
1872 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001873 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001874}
1875
Geoff Langef7b0162014-09-04 13:29:23 -04001876gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1877 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001878{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001879 ASSERT(target == GL_TEXTURE_3D);
1880
Jamie Madill82bf0c52014-10-03 11:50:53 -04001881 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001882 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001883
Jamie Madille76bdda2014-10-20 17:13:52 -04001884 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001885 {
Geoff Langef7b0162014-09-04 13:29:23 -04001886 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1887 if (error.isError())
1888 {
1889 return error;
1890 }
1891
Brandon Jones78b1acd2014-07-15 15:33:07 -07001892 mDirtyImages = true;
1893 }
1894 else
1895 {
Geoff Langef7b0162014-09-04 13:29:23 -04001896 gl::Error error = ensureRenderTarget();
1897 if (error.isError())
1898 {
1899 return error;
1900 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001901
1902 if (isValidLevel(level))
1903 {
Geoff Langef7b0162014-09-04 13:29:23 -04001904 error = updateStorageLevel(level);
1905 if (error.isError())
1906 {
1907 return error;
1908 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909
Geoff Langef7b0162014-09-04 13:29:23 -04001910 error = mRenderer->copyImage3D(source, sourceRect,
1911 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1912 xoffset, yoffset, zoffset, mTexStorage, level);
1913 if (error.isError())
1914 {
1915 return error;
1916 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917 }
1918 }
Geoff Langef7b0162014-09-04 13:29:23 -04001919
1920 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001921}
1922
Geoff Lang1f8532b2014-09-05 09:46:13 -04001923gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001924{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001925 ASSERT(target == GL_TEXTURE_3D);
1926
Brandon Jones78b1acd2014-07-15 15:33:07 -07001927 for (int level = 0; level < levels; level++)
1928 {
1929 GLsizei levelWidth = std::max(1, width >> level);
1930 GLsizei levelHeight = std::max(1, height >> level);
1931 GLsizei levelDepth = std::max(1, depth >> level);
Austin Kinross049743a2014-12-23 13:05:11 -08001932 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001933 }
1934
1935 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1936 {
Austin Kinross049743a2014-12-23 13:05:11 -08001937 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001938 }
1939
Geoff Lang1f8532b2014-09-05 09:46:13 -04001940 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001941 bool renderTarget = IsRenderTargetUsage(mUsage);
1942 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001943
1944 gl::Error error = setCompleteTexStorage(storage);
1945 if (error.isError())
1946 {
1947 SafeDelete(storage);
1948 return error;
1949 }
1950
1951 mImmutable = true;
1952
1953 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001954}
1955
Brandon Jones6053a522014-07-25 16:22:09 -07001956void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001957{
Brandon Jones6053a522014-07-25 16:22:09 -07001958 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001959}
1960
Brandon Jones6053a522014-07-25 16:22:09 -07001961void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001962{
Brandon Jones6053a522014-07-25 16:22:09 -07001963 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001964}
1965
Brandon Jones6053a522014-07-25 16:22:09 -07001966
Jamie Madill4aa79e12014-09-29 10:46:14 -04001967void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001968{
1969 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1970 int levelCount = mipLevels();
1971 for (int level = 1; level < levelCount; level++)
1972 {
1973 redefineImage(level, getBaseLevelInternalFormat(),
1974 std::max(getBaseLevelWidth() >> level, 1),
1975 std::max(getBaseLevelHeight() >> level, 1),
1976 std::max(getBaseLevelDepth() >> level, 1));
1977 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001978}
1979
Jamie Madillac7579c2014-09-17 16:59:33 -04001980unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001981{
Geoff Langef7b0162014-09-04 13:29:23 -04001982 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001983}
1984
Geoff Lang64f23f62014-09-10 14:40:12 -04001985gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001986{
1987 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001988 gl::Error error = ensureRenderTarget();
1989 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001990 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001991 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001992 }
1993
Jamie Madillac7579c2014-09-17 16:59:33 -04001994 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001995 {
Geoff Langef7b0162014-09-04 13:29:23 -04001996 error = updateStorage();
1997 if (error.isError())
1998 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001999 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002000 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002001 }
2002 else
2003 {
Geoff Langef7b0162014-09-04 13:29:23 -04002004 error = updateStorageLevel(index.mipIndex);
2005 if (error.isError())
2006 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002007 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002008 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002009 }
2010
Geoff Lang64f23f62014-09-10 14:40:12 -04002011 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002012}
2013
Geoff Langef7b0162014-09-04 13:29:23 -04002014gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002015{
2016 // Only initialize the first time this texture is used as a render target or shader resource
2017 if (mTexStorage)
2018 {
Geoff Langef7b0162014-09-04 13:29:23 -04002019 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020 }
2021
2022 // do not attempt to create storage for nonexistant data
2023 if (!isLevelComplete(0))
2024 {
Geoff Langef7b0162014-09-04 13:29:23 -04002025 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002026 }
2027
2028 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2029
Jamie Madill30d6c252014-11-13 10:03:33 -05002030 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002031 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2032 if (error.isError())
2033 {
2034 return error;
2035 }
2036
2037 error = setCompleteTexStorage(storage);
2038 if (error.isError())
2039 {
2040 SafeDelete(storage);
2041 return error;
2042 }
2043
Brandon Jones78b1acd2014-07-15 15:33:07 -07002044 ASSERT(mTexStorage);
2045
2046 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002047 error = updateStorage();
2048 if (error.isError())
2049 {
2050 return error;
2051 }
2052
2053 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002054}
2055
Geoff Langef7b0162014-09-04 13:29:23 -04002056gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002057{
2058 GLsizei width = getBaseLevelWidth();
2059 GLsizei height = getBaseLevelHeight();
2060 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002061 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062
2063 ASSERT(width > 0 && height > 0 && depth > 0);
2064
2065 // use existing storage level count, when previously specified by TexStorage*D
2066 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2067
Geoff Langef7b0162014-09-04 13:29:23 -04002068 // TODO: Verify creation of the storage succeeded
2069 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2070
2071 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002072}
2073
Geoff Langef7b0162014-09-04 13:29:23 -04002074gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002075{
2076 SafeDelete(mTexStorage);
2077 mTexStorage = newCompleteTexStorage;
2078 mDirtyImages = true;
2079
2080 // We do not support managed 3D storage, as that is D3D9/ES2-only
2081 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002082
2083 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002084}
2085
Geoff Langef7b0162014-09-04 13:29:23 -04002086gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002087{
2088 ASSERT(mTexStorage != NULL);
2089 GLint storageLevels = mTexStorage->getLevelCount();
2090 for (int level = 0; level < storageLevels; level++)
2091 {
2092 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2093 {
Geoff Langef7b0162014-09-04 13:29:23 -04002094 gl::Error error = updateStorageLevel(level);
2095 if (error.isError())
2096 {
2097 return error;
2098 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099 }
2100 }
Geoff Langef7b0162014-09-04 13:29:23 -04002101
2102 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002103}
2104
Brandon Jones78b1acd2014-07-15 15:33:07 -07002105bool TextureD3D_3D::isValidLevel(int level) const
2106{
2107 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2108}
2109
2110bool TextureD3D_3D::isLevelComplete(int level) const
2111{
2112 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2113
2114 if (isImmutable())
2115 {
2116 return true;
2117 }
2118
2119 GLsizei width = getBaseLevelWidth();
2120 GLsizei height = getBaseLevelHeight();
2121 GLsizei depth = getBaseLevelDepth();
2122
2123 if (width <= 0 || height <= 0 || depth <= 0)
2124 {
2125 return false;
2126 }
2127
2128 if (level == 0)
2129 {
2130 return true;
2131 }
2132
2133 ImageD3D *levelImage = mImageArray[level];
2134
2135 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2136 {
2137 return false;
2138 }
2139
2140 if (levelImage->getWidth() != std::max(1, width >> level))
2141 {
2142 return false;
2143 }
2144
2145 if (levelImage->getHeight() != std::max(1, height >> level))
2146 {
2147 return false;
2148 }
2149
2150 if (levelImage->getDepth() != std::max(1, depth >> level))
2151 {
2152 return false;
2153 }
2154
2155 return true;
2156}
2157
Jamie Madille76bdda2014-10-20 17:13:52 -04002158bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2159{
2160 return isLevelComplete(index.mipIndex);
2161}
2162
Geoff Langef7b0162014-09-04 13:29:23 -04002163gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002164{
2165 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2166 ASSERT(isLevelComplete(level));
2167
2168 if (mImageArray[level]->isDirty())
2169 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002170 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2171 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002172 gl::Error error = commitRegion(index, region);
2173 if (error.isError())
2174 {
2175 return error;
2176 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002177 }
Geoff Langef7b0162014-09-04 13:29:23 -04002178
2179 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002180}
2181
2182void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2183{
2184 // If there currently is a corresponding storage texture image, it has these parameters
2185 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2186 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2187 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2188 const GLenum storageFormat = getBaseLevelInternalFormat();
2189
Austin Kinross049743a2014-12-23 13:05:11 -08002190 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, width, height, depth, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002191
2192 if (mTexStorage)
2193 {
2194 const int storageLevels = mTexStorage->getLevelCount();
2195
2196 if ((level >= storageLevels && storageLevels != 0) ||
2197 width != storageWidth ||
2198 height != storageHeight ||
2199 depth != storageDepth ||
2200 internalformat != storageFormat) // Discard mismatched storage
2201 {
2202 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2203 {
2204 mImageArray[i]->markDirty();
2205 }
2206
2207 SafeDelete(mTexStorage);
2208 mDirtyImages = true;
2209 }
2210 }
2211}
2212
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002213gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2214{
2215 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2216 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2217}
Brandon Jones142ec422014-07-16 10:31:30 -07002218
Jamie Madillcb83dc12014-09-29 10:46:12 -04002219gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2220{
2221 // The "layer" here does not apply to 3D images. We use one Image per mip.
2222 return gl::ImageIndex::Make3D(mip);
2223}
2224
Jamie Madill710e5772014-10-20 17:13:53 -04002225bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2226{
2227 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2228 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2229}
2230
Jamie Madill93e13fb2014-11-06 15:27:25 -05002231TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002232 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002233{
2234 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2235 {
2236 mLayerCounts[level] = 0;
2237 mImageArray[level] = NULL;
2238 }
2239}
2240
2241TextureD3D_2DArray::~TextureD3D_2DArray()
2242{
Austin Kinross69822602014-08-12 15:51:37 -07002243 // Delete the Images before the TextureStorage.
2244 // Images might be relying on the TextureStorage for some of their data.
2245 // 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 -07002246 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002247 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002248}
2249
Brandon Jones142ec422014-07-16 10:31:30 -07002250Image *TextureD3D_2DArray::getImage(int level, int layer) const
2251{
2252 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002253 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2254 layer < mLayerCounts[level]);
2255 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002256}
2257
Jamie Madillfeda4d22014-09-17 13:03:29 -04002258Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2259{
2260 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002261 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2262 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002263 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002264 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002265}
2266
Brandon Jones142ec422014-07-16 10:31:30 -07002267GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2268{
2269 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2270 return mLayerCounts[level];
2271}
2272
Brandon Jones142ec422014-07-16 10:31:30 -07002273GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2274{
2275 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2276}
2277
2278GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2279{
2280 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2281}
2282
Brandon Jones142ec422014-07-16 10:31:30 -07002283GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2284{
2285 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2286}
2287
2288bool TextureD3D_2DArray::isDepth(GLint level) const
2289{
Geoff Lang5d601382014-07-22 15:14:06 -04002290 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002291}
2292
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002293gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2294 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2295 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002296{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002297 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2298
Geoff Lang5d601382014-07-22 15:14:06 -04002299 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2300
Brandon Jones142ec422014-07-16 10:31:30 -07002301 redefineImage(level, sizedInternalFormat, width, height, depth);
2302
Geoff Lang5d601382014-07-22 15:14:06 -04002303 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2304 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002305
2306 for (int i = 0; i < depth; i++)
2307 {
2308 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002309 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2310 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002311 if (error.isError())
2312 {
2313 return error;
2314 }
Brandon Jones142ec422014-07-16 10:31:30 -07002315 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002316
2317 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002318}
2319
Geoff Langb5348332014-09-02 13:16:34 -04002320gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2321 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002322 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002323{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002324 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2325
Brandon Jones142ec422014-07-16 10:31:30 -07002326 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2327 redefineImage(level, format, width, height, depth);
2328
Geoff Lang5d601382014-07-22 15:14:06 -04002329 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2330 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002331
2332 for (int i = 0; i < depth; i++)
2333 {
2334 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002335 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002336 if (error.isError())
2337 {
2338 return error;
2339 }
Brandon Jones142ec422014-07-16 10:31:30 -07002340 }
Geoff Langb5348332014-09-02 13:16:34 -04002341
2342 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002343}
2344
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002345gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2346 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2347 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002348{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002349 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2350
Geoff Lang5d601382014-07-22 15:14:06 -04002351 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2352 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002353
2354 for (int i = 0; i < depth; i++)
2355 {
2356 int layer = zoffset + i;
2357 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2358
Jamie Madillfeda4d22014-09-17 13:03:29 -04002359 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madillf8fccb32014-11-12 15:05:26 -05002360 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
Jamie Madille6b6da02014-10-02 11:03:14 -04002361 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002362 if (error.isError())
2363 {
2364 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002365 }
2366 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002367
2368 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002369}
2370
Geoff Langb5348332014-09-02 13:16:34 -04002371gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2372 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002373 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002374{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002375 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2376
Geoff Lang5d601382014-07-22 15:14:06 -04002377 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2378 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002379
2380 for (int i = 0; i < depth; i++)
2381 {
2382 int layer = zoffset + i;
2383 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2384
Jamie Madillc751d1e2014-10-21 17:46:29 -04002385 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]);
Geoff Langb5348332014-09-02 13:16:34 -04002386 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002387 {
Geoff Langb5348332014-09-02 13:16:34 -04002388 return error;
2389 }
2390
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002391 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2392 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2393 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002394 if (error.isError())
2395 {
2396 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002397 }
2398 }
Geoff Langb5348332014-09-02 13:16:34 -04002399
2400 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002401}
2402
Geoff Langef7b0162014-09-04 13:29:23 -04002403gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002404{
2405 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002406 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002407}
2408
Geoff Langef7b0162014-09-04 13:29:23 -04002409gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002410{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002411 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2412
Jamie Madill82bf0c52014-10-03 11:50:53 -04002413 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002414 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002415
Jamie Madille76bdda2014-10-20 17:13:52 -04002416 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002417 {
Geoff Langef7b0162014-09-04 13:29:23 -04002418 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2419 if (error.isError())
2420 {
2421 return error;
2422 }
2423
Brandon Jones142ec422014-07-16 10:31:30 -07002424 mDirtyImages = true;
2425 }
2426 else
2427 {
Geoff Langef7b0162014-09-04 13:29:23 -04002428 gl::Error error = ensureRenderTarget();
2429 if (error.isError())
2430 {
2431 return error;
2432 }
Brandon Jones142ec422014-07-16 10:31:30 -07002433
2434 if (isValidLevel(level))
2435 {
Geoff Langef7b0162014-09-04 13:29:23 -04002436 error = updateStorageLevel(level);
2437 if (error.isError())
2438 {
2439 return error;
2440 }
Brandon Jones142ec422014-07-16 10:31:30 -07002441
Geoff Langef7b0162014-09-04 13:29:23 -04002442 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2443 xoffset, yoffset, zoffset, mTexStorage, level);
2444 if (error.isError())
2445 {
2446 return error;
2447 }
Brandon Jones142ec422014-07-16 10:31:30 -07002448 }
2449 }
Geoff Langef7b0162014-09-04 13:29:23 -04002450 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002451}
2452
Geoff Lang1f8532b2014-09-05 09:46:13 -04002453gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002454{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002455 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2456
Brandon Jones142ec422014-07-16 10:31:30 -07002457 deleteImages();
2458
2459 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2460 {
2461 GLsizei levelWidth = std::max(1, width >> level);
2462 GLsizei levelHeight = std::max(1, height >> level);
2463
2464 mLayerCounts[level] = (level < levels ? depth : 0);
2465
2466 if (mLayerCounts[level] > 0)
2467 {
2468 // Create new images for this level
2469 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2470
2471 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2472 {
2473 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Austin Kinross049743a2014-12-23 13:05:11 -08002474 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
Brandon Jones142ec422014-07-16 10:31:30 -07002475 levelHeight, 1, true);
2476 }
2477 }
2478 }
2479
Geoff Lang1f8532b2014-09-05 09:46:13 -04002480 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002481 bool renderTarget = IsRenderTargetUsage(mUsage);
2482 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002483
2484 gl::Error error = setCompleteTexStorage(storage);
2485 if (error.isError())
2486 {
2487 SafeDelete(storage);
2488 return error;
2489 }
2490
2491 mImmutable = true;
2492
2493 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002494}
2495
Brandon Jones6053a522014-07-25 16:22:09 -07002496void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002497{
Brandon Jones6053a522014-07-25 16:22:09 -07002498 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002499}
2500
Brandon Jones6053a522014-07-25 16:22:09 -07002501void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002502{
Brandon Jones6053a522014-07-25 16:22:09 -07002503 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002504}
2505
Brandon Jones6053a522014-07-25 16:22:09 -07002506
Jamie Madill4aa79e12014-09-29 10:46:14 -04002507void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002508{
2509 int baseWidth = getBaseLevelWidth();
2510 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002511 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002512 GLenum baseFormat = getBaseLevelInternalFormat();
2513
2514 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2515 int levelCount = mipLevels();
2516 for (int level = 1; level < levelCount; level++)
2517 {
2518 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2519 }
Brandon Jones142ec422014-07-16 10:31:30 -07002520}
2521
Jamie Madillac7579c2014-09-17 16:59:33 -04002522unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002523{
Geoff Langef7b0162014-09-04 13:29:23 -04002524 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002525}
2526
Geoff Lang64f23f62014-09-10 14:40:12 -04002527gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002528{
2529 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002530 gl::Error error = ensureRenderTarget();
2531 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002532 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002533 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002534 }
2535
Geoff Langef7b0162014-09-04 13:29:23 -04002536 error = updateStorageLevel(index.mipIndex);
2537 if (error.isError())
2538 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002539 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002540 }
2541
Geoff Lang64f23f62014-09-10 14:40:12 -04002542 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002543}
2544
Geoff Langef7b0162014-09-04 13:29:23 -04002545gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002546{
2547 // Only initialize the first time this texture is used as a render target or shader resource
2548 if (mTexStorage)
2549 {
Geoff Langef7b0162014-09-04 13:29:23 -04002550 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002551 }
2552
2553 // do not attempt to create storage for nonexistant data
2554 if (!isLevelComplete(0))
2555 {
Geoff Langef7b0162014-09-04 13:29:23 -04002556 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002557 }
2558
2559 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2560
Geoff Langef7b0162014-09-04 13:29:23 -04002561 TextureStorage *storage = NULL;
2562 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2563 if (error.isError())
2564 {
2565 return error;
2566 }
2567
2568 error = setCompleteTexStorage(storage);
2569 if (error.isError())
2570 {
2571 SafeDelete(storage);
2572 return error;
2573 }
2574
Brandon Jones142ec422014-07-16 10:31:30 -07002575 ASSERT(mTexStorage);
2576
2577 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002578 error = updateStorage();
2579 if (error.isError())
2580 {
2581 return error;
2582 }
2583
2584 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002585}
2586
Geoff Langef7b0162014-09-04 13:29:23 -04002587gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002588{
2589 GLsizei width = getBaseLevelWidth();
2590 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002591 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002592 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002593
2594 ASSERT(width > 0 && height > 0 && depth > 0);
2595
2596 // use existing storage level count, when previously specified by TexStorage*D
2597 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2598
Geoff Langef7b0162014-09-04 13:29:23 -04002599 // TODO(geofflang): Verify storage creation succeeds
2600 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2601
2602 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002603}
2604
Geoff Langef7b0162014-09-04 13:29:23 -04002605gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002606{
2607 SafeDelete(mTexStorage);
2608 mTexStorage = newCompleteTexStorage;
2609 mDirtyImages = true;
2610
2611 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2612 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002613
2614 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002615}
2616
Geoff Langef7b0162014-09-04 13:29:23 -04002617gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002618{
2619 ASSERT(mTexStorage != NULL);
2620 GLint storageLevels = mTexStorage->getLevelCount();
2621 for (int level = 0; level < storageLevels; level++)
2622 {
2623 if (isLevelComplete(level))
2624 {
Geoff Langef7b0162014-09-04 13:29:23 -04002625 gl::Error error = updateStorageLevel(level);
2626 if (error.isError())
2627 {
2628 return error;
2629 }
Brandon Jones142ec422014-07-16 10:31:30 -07002630 }
2631 }
Geoff Langef7b0162014-09-04 13:29:23 -04002632
2633 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002634}
2635
Brandon Jones142ec422014-07-16 10:31:30 -07002636bool TextureD3D_2DArray::isValidLevel(int level) const
2637{
2638 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2639}
2640
2641bool TextureD3D_2DArray::isLevelComplete(int level) const
2642{
2643 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2644
2645 if (isImmutable())
2646 {
2647 return true;
2648 }
2649
2650 GLsizei width = getBaseLevelWidth();
2651 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002652 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002653
2654 if (width <= 0 || height <= 0 || layers <= 0)
2655 {
2656 return false;
2657 }
2658
2659 if (level == 0)
2660 {
2661 return true;
2662 }
2663
2664 if (getInternalFormat(level) != getInternalFormat(0))
2665 {
2666 return false;
2667 }
2668
2669 if (getWidth(level) != std::max(1, width >> level))
2670 {
2671 return false;
2672 }
2673
2674 if (getHeight(level) != std::max(1, height >> level))
2675 {
2676 return false;
2677 }
2678
Jamie Madill3269bcb2014-09-30 16:33:52 -04002679 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002680 {
2681 return false;
2682 }
2683
2684 return true;
2685}
2686
Jamie Madille76bdda2014-10-20 17:13:52 -04002687bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2688{
2689 return isLevelComplete(index.mipIndex);
2690}
2691
Geoff Langef7b0162014-09-04 13:29:23 -04002692gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002693{
2694 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2695 ASSERT(isLevelComplete(level));
2696
2697 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2698 {
2699 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2700 if (mImageArray[level][layer]->isDirty())
2701 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002702 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2703 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002704 gl::Error error = commitRegion(index, region);
2705 if (error.isError())
2706 {
2707 return error;
2708 }
Brandon Jones142ec422014-07-16 10:31:30 -07002709 }
2710 }
Geoff Langef7b0162014-09-04 13:29:23 -04002711
2712 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002713}
2714
2715void TextureD3D_2DArray::deleteImages()
2716{
2717 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2718 {
2719 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2720 {
2721 delete mImageArray[level][layer];
2722 }
2723 delete[] mImageArray[level];
2724 mImageArray[level] = NULL;
2725 mLayerCounts[level] = 0;
2726 }
2727}
2728
2729void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2730{
2731 // If there currently is a corresponding storage texture image, it has these parameters
2732 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2733 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002734 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002735 const GLenum storageFormat = getBaseLevelInternalFormat();
2736
2737 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2738 {
2739 delete mImageArray[level][layer];
2740 }
2741 delete[] mImageArray[level];
2742 mImageArray[level] = NULL;
2743 mLayerCounts[level] = depth;
2744
2745 if (depth > 0)
2746 {
2747 mImageArray[level] = new ImageD3D*[depth]();
2748
2749 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2750 {
2751 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Austin Kinross049743a2014-12-23 13:05:11 -08002752 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
Brandon Jones142ec422014-07-16 10:31:30 -07002753 }
2754 }
2755
2756 if (mTexStorage)
2757 {
2758 const int storageLevels = mTexStorage->getLevelCount();
2759
2760 if ((level >= storageLevels && storageLevels != 0) ||
2761 width != storageWidth ||
2762 height != storageHeight ||
2763 depth != storageDepth ||
2764 internalformat != storageFormat) // Discard mismatched storage
2765 {
2766 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2767 {
2768 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2769 {
2770 mImageArray[level][layer]->markDirty();
2771 }
2772 }
2773
2774 delete mTexStorage;
2775 mTexStorage = NULL;
2776 mDirtyImages = true;
2777 }
2778 }
2779}
2780
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002781gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2782{
2783 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2784}
2785
Jamie Madillcb83dc12014-09-29 10:46:12 -04002786gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2787{
2788 return gl::ImageIndex::Make2DArray(mip, layer);
2789}
2790
Jamie Madill710e5772014-10-20 17:13:53 -04002791bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2792{
2793 // Check for having a storage and the right type of index
2794 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2795 {
2796 return false;
2797 }
2798
2799 // Check the mip index
2800 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2801 {
2802 return false;
2803 }
2804
2805 // Check the layer index
2806 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2807}
2808
Brandon Jones78b1acd2014-07-15 15:33:07 -07002809}