blob: 1dec77f9ec78f65ca28c931b63937011fff10f93 [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
580GLenum TextureD3D_2D::getActualFormat(GLint level) const
581{
582 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
583 return mImageArray[level]->getActualFormat();
584 else
585 return GL_NONE;
586}
587
588bool TextureD3D_2D::isDepth(GLint level) const
589{
Geoff Lang5d601382014-07-22 15:14:06 -0400590 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700591}
592
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400593gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
594 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
595 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700597 ASSERT(target == GL_TEXTURE_2D && depth == 1);
598
Geoff Lang5d601382014-07-22 15:14:06 -0400599 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
600
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700601 bool fastUnpacked = false;
602
Brandon Jonescef06ff2014-08-05 13:27:48 -0700603 redefineImage(level, sizedInternalFormat, width, height);
604
Jamie Madillba6bc952014-10-06 10:56:22 -0400605 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
606
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700607 // Attempt a fast gpu copy of the pixel data to the surface
608 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
609 {
610 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400611 RenderTarget *destRenderTarget = NULL;
612 gl::Error error = getRenderTarget(index, &destRenderTarget);
613 if (error.isError())
614 {
615 return error;
616 }
617
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700618 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
619
Geoff Lang64f23f62014-09-10 14:40:12 -0400620 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
621 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400623 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700624 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400625
626 // Ensure we don't overwrite our newly initialized data
627 mImageArray[level]->markClean();
628
629 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630 }
631
632 if (!fastUnpacked)
633 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400634 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400635 if (error.isError())
636 {
637 return error;
638 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400640
641 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700642}
643
Geoff Langb5348332014-09-02 13:16:34 -0400644gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
645 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400646 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700647{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700648 ASSERT(target == GL_TEXTURE_2D && depth == 1);
649
650 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
651 redefineImage(level, format, width, height);
652
Jamie Madillc751d1e2014-10-21 17:46:29 -0400653 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654}
655
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400656gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
657 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
658 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700659{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700660 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
661
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662 bool fastUnpacked = false;
663
Jamie Madillac7579c2014-09-17 16:59:33 -0400664 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400665 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700666 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
667 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400668 RenderTarget *renderTarget = NULL;
669 gl::Error error = getRenderTarget(index, &renderTarget);
670 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400672 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700673 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400674
675 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
676 if (error.isError())
677 {
678 return error;
679 }
680
681 // Ensure we don't overwrite our newly initialized data
682 mImageArray[level]->markClean();
683
684 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700685 }
686
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400687 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400689 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
690 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400692
693 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694}
695
Geoff Langb5348332014-09-02 13:16:34 -0400696gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
697 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400698 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700699{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700700 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
701
Jamie Madillc751d1e2014-10-21 17:46:29 -0400702 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -0400703 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704 {
Geoff Langb5348332014-09-02 13:16:34 -0400705 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700706 }
Geoff Langb5348332014-09-02 13:16:34 -0400707
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400708 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
709 gl::Box region(xoffset, yoffset, 0, width, height, 1);
710 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700711}
712
Geoff Langef7b0162014-09-04 13:29:23 -0400713gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
714 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700715{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700716 ASSERT(target == GL_TEXTURE_2D);
717
718 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
719 redefineImage(level, sizedInternalFormat, width, height);
720
Jamie Madill82bf0c52014-10-03 11:50:53 -0400721 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400722 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400723
Jamie Madille76bdda2014-10-20 17:13:52 -0400724 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700725 {
Geoff Langef7b0162014-09-04 13:29:23 -0400726 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
727 if (error.isError())
728 {
729 return error;
730 }
731
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700732 mDirtyImages = true;
733 }
734 else
735 {
Geoff Langef7b0162014-09-04 13:29:23 -0400736 gl::Error error = ensureRenderTarget();
737 if (error.isError())
738 {
739 return error;
740 }
741
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742 mImageArray[level]->markClean();
743
744 if (width != 0 && height != 0 && isValidLevel(level))
745 {
Geoff Langef7b0162014-09-04 13:29:23 -0400746 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
747 if (error.isError())
748 {
749 return error;
750 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700751 }
752 }
Geoff Langef7b0162014-09-04 13:29:23 -0400753
754 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700755}
756
Geoff Langef7b0162014-09-04 13:29:23 -0400757gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
758 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700759{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700760 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
761
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700762 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
763 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700764
Jamie Madill82bf0c52014-10-03 11:50:53 -0400765 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400766 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400767
Jamie Madille76bdda2014-10-20 17:13:52 -0400768 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700769 {
Geoff Langef7b0162014-09-04 13:29:23 -0400770 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
771 if (error.isError())
772 {
773 return error;
774 }
775
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700776 mDirtyImages = true;
777 }
778 else
779 {
Geoff Langef7b0162014-09-04 13:29:23 -0400780 gl::Error error = ensureRenderTarget();
781 if (error.isError())
782 {
783 return error;
784 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785
786 if (isValidLevel(level))
787 {
Geoff Langef7b0162014-09-04 13:29:23 -0400788 error = updateStorageLevel(level);
789 if (error.isError())
790 {
791 return error;
792 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793
Geoff Langef7b0162014-09-04 13:29:23 -0400794 error = mRenderer->copyImage2D(source, sourceRect,
795 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
796 xoffset, yoffset, mTexStorage, level);
797 if (error.isError())
798 {
799 return error;
800 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700801 }
802 }
Geoff Langef7b0162014-09-04 13:29:23 -0400803
804 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700805}
806
Geoff Lang1f8532b2014-09-05 09:46:13 -0400807gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700808{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700809 ASSERT(target == GL_TEXTURE_2D && depth == 1);
810
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700811 for (int level = 0; level < levels; level++)
812 {
813 GLsizei levelWidth = std::max(1, width >> level);
814 GLsizei levelHeight = std::max(1, height >> level);
815 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
816 }
817
818 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
819 {
820 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
821 }
822
Geoff Lang1f8532b2014-09-05 09:46:13 -0400823 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400824 bool renderTarget = IsRenderTargetUsage(mUsage);
825 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400826
827 gl::Error error = setCompleteTexStorage(storage);
828 if (error.isError())
829 {
830 SafeDelete(storage);
831 return error;
832 }
833
834 mImmutable = true;
835
836 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700837}
838
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700839void TextureD3D_2D::bindTexImage(egl::Surface *surface)
840{
841 GLenum internalformat = surface->getFormat();
842
843 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
844
845 if (mTexStorage)
846 {
847 SafeDelete(mTexStorage);
848 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400849
Jamie Madillfb0580a2014-11-27 14:03:52 -0500850 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
851 ASSERT(surfaceD3D);
852
853 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700854
855 mDirtyImages = true;
856}
857
858void TextureD3D_2D::releaseTexImage()
859{
860 if (mTexStorage)
861 {
862 SafeDelete(mTexStorage);
863 }
864
865 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
866 {
867 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
868 }
869}
870
Jamie Madill4aa79e12014-09-29 10:46:14 -0400871void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700872{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700873 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700874 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700875 for (int level = 1; level < levelCount; level++)
876 {
877 redefineImage(level, getBaseLevelInternalFormat(),
878 std::max(getBaseLevelWidth() >> level, 1),
879 std::max(getBaseLevelHeight() >> level, 1));
880 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700881}
882
Jamie Madillac7579c2014-09-17 16:59:33 -0400883unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884{
Jamie Madillac7579c2014-09-17 16:59:33 -0400885 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400886 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700887}
888
Geoff Lang64f23f62014-09-10 14:40:12 -0400889gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700890{
Jamie Madillac7579c2014-09-17 16:59:33 -0400891 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700892
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700893 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400894 gl::Error error = ensureRenderTarget();
895 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700896 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400897 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700898 }
899
Geoff Langef7b0162014-09-04 13:29:23 -0400900 error = updateStorageLevel(index.mipIndex);
901 if (error.isError())
902 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400903 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400904 }
905
Geoff Lang64f23f62014-09-10 14:40:12 -0400906 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700907}
908
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700909bool TextureD3D_2D::isValidLevel(int level) const
910{
911 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
912}
913
914bool TextureD3D_2D::isLevelComplete(int level) const
915{
916 if (isImmutable())
917 {
918 return true;
919 }
920
Brandon Jones78b1acd2014-07-15 15:33:07 -0700921 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700922
923 GLsizei width = baseImage->getWidth();
924 GLsizei height = baseImage->getHeight();
925
926 if (width <= 0 || height <= 0)
927 {
928 return false;
929 }
930
931 // The base image level is complete if the width and height are positive
932 if (level == 0)
933 {
934 return true;
935 }
936
937 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700938 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700939
940 if (image->getInternalFormat() != baseImage->getInternalFormat())
941 {
942 return false;
943 }
944
945 if (image->getWidth() != std::max(1, width >> level))
946 {
947 return false;
948 }
949
950 if (image->getHeight() != std::max(1, height >> level))
951 {
952 return false;
953 }
954
955 return true;
956}
957
Jamie Madille76bdda2014-10-20 17:13:52 -0400958bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
959{
960 return isLevelComplete(index.mipIndex);
961}
962
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700963// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400964gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700965{
966 // Only initialize the first time this texture is used as a render target or shader resource
967 if (mTexStorage)
968 {
Geoff Langef7b0162014-09-04 13:29:23 -0400969 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700970 }
971
972 // do not attempt to create storage for nonexistant data
973 if (!isLevelComplete(0))
974 {
Geoff Langef7b0162014-09-04 13:29:23 -0400975 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700976 }
977
978 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
979
Geoff Langef7b0162014-09-04 13:29:23 -0400980 TextureStorage *storage = NULL;
981 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
982 if (error.isError())
983 {
984 return error;
985 }
986
987 error = setCompleteTexStorage(storage);
988 if (error.isError())
989 {
990 SafeDelete(storage);
991 return error;
992 }
993
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700994 ASSERT(mTexStorage);
995
996 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400997 error = updateStorage();
998 if (error.isError())
999 {
1000 return error;
1001 }
1002
1003 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001004}
1005
Geoff Langef7b0162014-09-04 13:29:23 -04001006gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001007{
1008 GLsizei width = getBaseLevelWidth();
1009 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001010 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001011
1012 ASSERT(width > 0 && height > 0);
1013
1014 // use existing storage level count, when previously specified by TexStorage*D
1015 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1016
Geoff Langef7b0162014-09-04 13:29:23 -04001017 // TODO(geofflang): Determine if the texture creation succeeded
1018 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
1019
1020 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001021}
1022
Geoff Langef7b0162014-09-04 13:29:23 -04001023gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001024{
Geoff Langef7b0162014-09-04 13:29:23 -04001025 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001026 {
Geoff Langef7b0162014-09-04 13:29:23 -04001027 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001028 {
Geoff Langef7b0162014-09-04 13:29:23 -04001029 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1030 if (error.isError())
1031 {
1032 return error;
1033 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001034 }
1035 }
1036
Geoff Langef7b0162014-09-04 13:29:23 -04001037 SafeDelete(mTexStorage);
1038 mTexStorage = newCompleteTexStorage;
1039
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001040 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001041
1042 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001043}
1044
Geoff Langef7b0162014-09-04 13:29:23 -04001045gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001046{
1047 ASSERT(mTexStorage != NULL);
1048 GLint storageLevels = mTexStorage->getLevelCount();
1049 for (int level = 0; level < storageLevels; level++)
1050 {
1051 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1052 {
Geoff Langef7b0162014-09-04 13:29:23 -04001053 gl::Error error = updateStorageLevel(level);
1054 if (error.isError())
1055 {
1056 return error;
1057 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001058 }
1059 }
Geoff Langef7b0162014-09-04 13:29:23 -04001060
1061 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001062}
1063
Geoff Langef7b0162014-09-04 13:29:23 -04001064gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001065{
1066 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1067 ASSERT(isLevelComplete(level));
1068
1069 if (mImageArray[level]->isDirty())
1070 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001071 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1072 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001073 gl::Error error = commitRegion(index, region);
1074 if (error.isError())
1075 {
1076 return error;
1077 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001078 }
Geoff Langef7b0162014-09-04 13:29:23 -04001079
1080 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001081}
1082
1083void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1084{
1085 // If there currently is a corresponding storage texture image, it has these parameters
1086 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1087 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1088 const GLenum storageFormat = getBaseLevelInternalFormat();
1089
1090 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1091
1092 if (mTexStorage)
1093 {
1094 const int storageLevels = mTexStorage->getLevelCount();
1095
1096 if ((level >= storageLevels && storageLevels != 0) ||
1097 width != storageWidth ||
1098 height != storageHeight ||
1099 internalformat != storageFormat) // Discard mismatched storage
1100 {
1101 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1102 {
1103 mImageArray[i]->markDirty();
1104 }
1105
1106 SafeDelete(mTexStorage);
1107 mDirtyImages = true;
1108 }
1109 }
1110}
1111
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001112gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1113{
1114 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1115}
Brandon Jones0511e802014-07-14 16:27:26 -07001116
Jamie Madillcb83dc12014-09-29 10:46:12 -04001117gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1118{
1119 // "layer" does not apply to 2D Textures.
1120 return gl::ImageIndex::Make2D(mip);
1121}
1122
Jamie Madill710e5772014-10-20 17:13:53 -04001123bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1124{
1125 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1126 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1127}
1128
Jamie Madill93e13fb2014-11-06 15:27:25 -05001129TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001130 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001131{
1132 for (int i = 0; i < 6; i++)
1133 {
1134 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1135 {
1136 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1137 }
1138 }
1139}
1140
1141TextureD3D_Cube::~TextureD3D_Cube()
1142{
Austin Kinross69822602014-08-12 15:51:37 -07001143 // Delete the Images before the TextureStorage.
1144 // Images might be relying on the TextureStorage for some of their data.
1145 // 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 -07001146 for (int i = 0; i < 6; i++)
1147 {
1148 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1149 {
1150 SafeDelete(mImageArray[i][j]);
1151 }
1152 }
Austin Kinross69822602014-08-12 15:51:37 -07001153
1154 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001155}
1156
Brandon Jonescef06ff2014-08-05 13:27:48 -07001157Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001158{
1159 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001160 ASSERT(layer < 6);
1161 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001162}
1163
Jamie Madillfeda4d22014-09-17 13:03:29 -04001164Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1165{
1166 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1167 ASSERT(index.layerIndex < 6);
1168 return mImageArray[index.layerIndex][index.mipIndex];
1169}
1170
Brandon Jonescef06ff2014-08-05 13:27:48 -07001171GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001172{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001173 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1174 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001175}
1176
Brandon Jonescef06ff2014-08-05 13:27:48 -07001177GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001178{
1179 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001180 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001181 else
1182 return GL_NONE;
1183}
1184
Brandon Jonescef06ff2014-08-05 13:27:48 -07001185bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001186{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001187 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001188}
1189
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001190gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1191 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1192 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001193{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001194 ASSERT(depth == 1);
1195
Geoff Lang5d601382014-07-22 15:14:06 -04001196 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001197 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001198
Jamie Madillba6bc952014-10-06 10:56:22 -04001199 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001200
Jamie Madillba6bc952014-10-06 10:56:22 -04001201 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001202}
1203
Geoff Langb5348332014-09-02 13:16:34 -04001204gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1205 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001206 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001207{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001208 ASSERT(depth == 1);
1209
Brandon Jones0511e802014-07-14 16:27:26 -07001210 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001211 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1212
Brandon Jones0511e802014-07-14 16:27:26 -07001213 redefineImage(faceIndex, level, format, width, height);
1214
Jamie Madillc751d1e2014-10-21 17:46:29 -04001215 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001216}
1217
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001218gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1219 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1220 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001221{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001222 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001223 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001224 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001225}
1226
Geoff Langb5348332014-09-02 13:16:34 -04001227gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1228 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001229 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001230{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001231 ASSERT(depth == 1 && zoffset == 0);
1232
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001233 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001234
Jamie Madillc751d1e2014-10-21 17:46:29 -04001235 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 -04001236 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001237 {
Geoff Langb5348332014-09-02 13:16:34 -04001238 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001239 }
Geoff Langb5348332014-09-02 13:16:34 -04001240
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001241 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1242 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001243}
1244
Geoff Langef7b0162014-09-04 13:29:23 -04001245gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1246 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001247{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001248 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001249 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1250
Brandon Jones0511e802014-07-14 16:27:26 -07001251 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1252
Jamie Madill82bf0c52014-10-03 11:50:53 -04001253 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001254 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001255
Jamie Madille76bdda2014-10-20 17:13:52 -04001256 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001257 {
Geoff Langef7b0162014-09-04 13:29:23 -04001258 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1259 if (error.isError())
1260 {
1261 return error;
1262 }
1263
Brandon Jones0511e802014-07-14 16:27:26 -07001264 mDirtyImages = true;
1265 }
1266 else
1267 {
Geoff Langef7b0162014-09-04 13:29:23 -04001268 gl::Error error = ensureRenderTarget();
1269 if (error.isError())
1270 {
1271 return error;
1272 }
1273
Brandon Jones0511e802014-07-14 16:27:26 -07001274 mImageArray[faceIndex][level]->markClean();
1275
1276 ASSERT(width == height);
1277
1278 if (width > 0 && isValidFaceLevel(faceIndex, level))
1279 {
Geoff Langef7b0162014-09-04 13:29:23 -04001280 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1281 if (error.isError())
1282 {
1283 return error;
1284 }
Brandon Jones0511e802014-07-14 16:27:26 -07001285 }
1286 }
Geoff Langef7b0162014-09-04 13:29:23 -04001287
1288 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001289}
1290
Geoff Langef7b0162014-09-04 13:29:23 -04001291gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1292 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001293{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001294 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001295
Jamie Madill82bf0c52014-10-03 11:50:53 -04001296 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001297 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001298
Jamie Madille76bdda2014-10-20 17:13:52 -04001299 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001300 {
Geoff Langef7b0162014-09-04 13:29:23 -04001301 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1302 if (error.isError())
1303 {
1304 return error;
1305 }
1306
Brandon Jones0511e802014-07-14 16:27:26 -07001307 mDirtyImages = true;
1308 }
1309 else
1310 {
Geoff Langef7b0162014-09-04 13:29:23 -04001311 gl::Error error = ensureRenderTarget();
1312 if (error.isError())
1313 {
1314 return error;
1315 }
Brandon Jones0511e802014-07-14 16:27:26 -07001316
1317 if (isValidFaceLevel(faceIndex, level))
1318 {
Geoff Langef7b0162014-09-04 13:29:23 -04001319 error = updateStorageFaceLevel(faceIndex, level);
1320 if (error.isError())
1321 {
1322 return error;
1323 }
Brandon Jones0511e802014-07-14 16:27:26 -07001324
Geoff Langef7b0162014-09-04 13:29:23 -04001325 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1326 xoffset, yoffset, mTexStorage, target, level);
1327 if (error.isError())
1328 {
1329 return error;
1330 }
Brandon Jones0511e802014-07-14 16:27:26 -07001331 }
1332 }
Geoff Langef7b0162014-09-04 13:29:23 -04001333
1334 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001335}
1336
Geoff Lang1f8532b2014-09-05 09:46:13 -04001337gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001338{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001339 ASSERT(width == height);
1340 ASSERT(depth == 1);
1341
Brandon Jones0511e802014-07-14 16:27:26 -07001342 for (int level = 0; level < levels; level++)
1343 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001344 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001345 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1346 {
1347 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1348 }
1349 }
1350
1351 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1352 {
1353 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1354 {
1355 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1356 }
1357 }
1358
Geoff Lang1f8532b2014-09-05 09:46:13 -04001359 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001360 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001361 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001362
1363 gl::Error error = setCompleteTexStorage(storage);
1364 if (error.isError())
1365 {
1366 SafeDelete(storage);
1367 return error;
1368 }
1369
1370 mImmutable = true;
1371
1372 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001373}
1374
Brandon Jones0511e802014-07-14 16:27:26 -07001375// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1376bool TextureD3D_Cube::isCubeComplete() const
1377{
1378 int baseWidth = getBaseLevelWidth();
1379 int baseHeight = getBaseLevelHeight();
1380 GLenum baseFormat = getBaseLevelInternalFormat();
1381
1382 if (baseWidth <= 0 || baseWidth != baseHeight)
1383 {
1384 return false;
1385 }
1386
1387 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1388 {
1389 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1390
1391 if (faceBaseImage.getWidth() != baseWidth ||
1392 faceBaseImage.getHeight() != baseHeight ||
1393 faceBaseImage.getInternalFormat() != baseFormat )
1394 {
1395 return false;
1396 }
1397 }
1398
1399 return true;
1400}
1401
Brandon Jones6053a522014-07-25 16:22:09 -07001402void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1403{
1404 UNREACHABLE();
1405}
1406
1407void TextureD3D_Cube::releaseTexImage()
1408{
1409 UNREACHABLE();
1410}
1411
1412
Jamie Madill4aa79e12014-09-29 10:46:14 -04001413void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001414{
1415 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1416 int levelCount = mipLevels();
1417 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1418 {
1419 for (int level = 1; level < levelCount; level++)
1420 {
1421 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1422 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1423 }
1424 }
Brandon Jones0511e802014-07-14 16:27:26 -07001425}
1426
Jamie Madillac7579c2014-09-17 16:59:33 -04001427unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001428{
Geoff Langef7b0162014-09-04 13:29:23 -04001429 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001430}
1431
Geoff Lang64f23f62014-09-10 14:40:12 -04001432gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001433{
Jamie Madillac7579c2014-09-17 16:59:33 -04001434 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001435
1436 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001437 gl::Error error = ensureRenderTarget();
1438 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001439 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001440 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001441 }
1442
Geoff Langef7b0162014-09-04 13:29:23 -04001443 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1444 if (error.isError())
1445 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001446 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001447 }
1448
Geoff Lang64f23f62014-09-10 14:40:12 -04001449 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001450}
1451
Geoff Langef7b0162014-09-04 13:29:23 -04001452gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001453{
1454 // Only initialize the first time this texture is used as a render target or shader resource
1455 if (mTexStorage)
1456 {
Geoff Langef7b0162014-09-04 13:29:23 -04001457 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001458 }
1459
1460 // do not attempt to create storage for nonexistant data
1461 if (!isFaceLevelComplete(0, 0))
1462 {
Geoff Langef7b0162014-09-04 13:29:23 -04001463 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001464 }
1465
1466 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1467
Geoff Langef7b0162014-09-04 13:29:23 -04001468 TextureStorage *storage = NULL;
1469 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1470 if (error.isError())
1471 {
1472 return error;
1473 }
1474
1475 error = setCompleteTexStorage(storage);
1476 if (error.isError())
1477 {
1478 SafeDelete(storage);
1479 return error;
1480 }
1481
Brandon Jones0511e802014-07-14 16:27:26 -07001482 ASSERT(mTexStorage);
1483
1484 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001485 error = updateStorage();
1486 if (error.isError())
1487 {
1488 return error;
1489 }
1490
1491 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001492}
1493
Geoff Langef7b0162014-09-04 13:29:23 -04001494gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001495{
1496 GLsizei size = getBaseLevelWidth();
1497
1498 ASSERT(size > 0);
1499
1500 // use existing storage level count, when previously specified by TexStorage*D
1501 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1502
Geoff Langef7b0162014-09-04 13:29:23 -04001503 // TODO (geofflang): detect if storage creation succeeded
1504 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1505
1506 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001507}
1508
Geoff Langef7b0162014-09-04 13:29:23 -04001509gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001510{
Geoff Langef7b0162014-09-04 13:29:23 -04001511 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001512 {
1513 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1514 {
Geoff Langef7b0162014-09-04 13:29:23 -04001515 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001516 {
Geoff Langef7b0162014-09-04 13:29:23 -04001517 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1518 if (error.isError())
1519 {
1520 return error;
1521 }
Brandon Jones0511e802014-07-14 16:27:26 -07001522 }
1523 }
1524 }
1525
Geoff Langef7b0162014-09-04 13:29:23 -04001526 SafeDelete(mTexStorage);
1527 mTexStorage = newCompleteTexStorage;
1528
Brandon Jones0511e802014-07-14 16:27:26 -07001529 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001530 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001531}
1532
Geoff Langef7b0162014-09-04 13:29:23 -04001533gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001534{
1535 ASSERT(mTexStorage != NULL);
1536 GLint storageLevels = mTexStorage->getLevelCount();
1537 for (int face = 0; face < 6; face++)
1538 {
1539 for (int level = 0; level < storageLevels; level++)
1540 {
1541 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1542 {
Geoff Langef7b0162014-09-04 13:29:23 -04001543 gl::Error error = updateStorageFaceLevel(face, level);
1544 if (error.isError())
1545 {
1546 return error;
1547 }
Brandon Jones0511e802014-07-14 16:27:26 -07001548 }
1549 }
1550 }
Geoff Langef7b0162014-09-04 13:29:23 -04001551
1552 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001553}
1554
Brandon Jones0511e802014-07-14 16:27:26 -07001555bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1556{
1557 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1558}
1559
Brandon Jones0511e802014-07-14 16:27:26 -07001560bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1561{
1562 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1563
1564 if (isImmutable())
1565 {
1566 return true;
1567 }
1568
1569 int baseSize = getBaseLevelWidth();
1570
1571 if (baseSize <= 0)
1572 {
1573 return false;
1574 }
1575
1576 // "isCubeComplete" checks for base level completeness and we must call that
1577 // to determine if any face at level 0 is complete. We omit that check here
1578 // to avoid re-checking cube-completeness for every face at level 0.
1579 if (level == 0)
1580 {
1581 return true;
1582 }
1583
1584 // Check that non-zero levels are consistent with the base level.
1585 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1586
1587 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1588 {
1589 return false;
1590 }
1591
1592 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1593 {
1594 return false;
1595 }
1596
1597 return true;
1598}
1599
Jamie Madille76bdda2014-10-20 17:13:52 -04001600bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1601{
1602 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1603}
1604
Geoff Langef7b0162014-09-04 13:29:23 -04001605gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001606{
1607 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1608 ImageD3D *image = mImageArray[faceIndex][level];
1609
1610 if (image->isDirty())
1611 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001612 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1613 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1614 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001615 gl::Error error = commitRegion(index, region);
1616 if (error.isError())
1617 {
1618 return error;
1619 }
Brandon Jones0511e802014-07-14 16:27:26 -07001620 }
Geoff Langef7b0162014-09-04 13:29:23 -04001621
1622 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001623}
1624
1625void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1626{
1627 // If there currently is a corresponding storage texture image, it has these parameters
1628 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1629 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1630 const GLenum storageFormat = getBaseLevelInternalFormat();
1631
1632 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1633
1634 if (mTexStorage)
1635 {
1636 const int storageLevels = mTexStorage->getLevelCount();
1637
1638 if ((level >= storageLevels && storageLevels != 0) ||
1639 width != storageWidth ||
1640 height != storageHeight ||
1641 internalformat != storageFormat) // Discard mismatched storage
1642 {
1643 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1644 {
1645 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1646 {
1647 mImageArray[faceIndex][level]->markDirty();
1648 }
1649 }
1650
1651 SafeDelete(mTexStorage);
1652
1653 mDirtyImages = true;
1654 }
1655 }
1656}
1657
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001658gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1659{
1660 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1661}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001662
Jamie Madillcb83dc12014-09-29 10:46:12 -04001663gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1664{
1665 // The "layer" of the image index corresponds to the cube face
1666 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1667}
1668
Jamie Madill710e5772014-10-20 17:13:53 -04001669bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1670{
1671 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1672 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1673}
1674
Jamie Madill93e13fb2014-11-06 15:27:25 -05001675TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001676 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001677{
1678 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1679 {
1680 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1681 }
1682}
1683
1684TextureD3D_3D::~TextureD3D_3D()
1685{
Austin Kinross69822602014-08-12 15:51:37 -07001686 // Delete the Images before the TextureStorage.
1687 // Images might be relying on the TextureStorage for some of their data.
1688 // 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 -07001689 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1690 {
1691 delete mImageArray[i];
1692 }
Austin Kinross69822602014-08-12 15:51:37 -07001693
1694 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001695}
1696
Brandon Jonescef06ff2014-08-05 13:27:48 -07001697Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001698{
1699 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001700 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001701 return mImageArray[level];
1702}
1703
Jamie Madillfeda4d22014-09-17 13:03:29 -04001704Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1705{
1706 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001707 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001708 ASSERT(index.type == GL_TEXTURE_3D);
1709 return mImageArray[index.mipIndex];
1710}
1711
Brandon Jonescef06ff2014-08-05 13:27:48 -07001712GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001713{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001714 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1715 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001716}
1717
Brandon Jones78b1acd2014-07-15 15:33:07 -07001718GLsizei TextureD3D_3D::getWidth(GLint level) const
1719{
1720 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1721 return mImageArray[level]->getWidth();
1722 else
1723 return 0;
1724}
1725
1726GLsizei TextureD3D_3D::getHeight(GLint level) const
1727{
1728 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1729 return mImageArray[level]->getHeight();
1730 else
1731 return 0;
1732}
1733
1734GLsizei TextureD3D_3D::getDepth(GLint level) const
1735{
1736 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1737 return mImageArray[level]->getDepth();
1738 else
1739 return 0;
1740}
1741
1742GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1743{
1744 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1745 return mImageArray[level]->getInternalFormat();
1746 else
1747 return GL_NONE;
1748}
1749
1750bool TextureD3D_3D::isDepth(GLint level) const
1751{
Geoff Lang5d601382014-07-22 15:14:06 -04001752 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001753}
1754
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001755gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1756 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1757 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001759 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001760 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1761
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762 redefineImage(level, sizedInternalFormat, width, height, depth);
1763
1764 bool fastUnpacked = false;
1765
Jamie Madillba6bc952014-10-06 10:56:22 -04001766 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1767
Brandon Jones78b1acd2014-07-15 15:33:07 -07001768 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1769 if (isFastUnpackable(unpack, sizedInternalFormat))
1770 {
1771 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001772 RenderTarget *destRenderTarget = NULL;
1773 gl::Error error = getRenderTarget(index, &destRenderTarget);
1774 if (error.isError())
1775 {
1776 return error;
1777 }
1778
Brandon Jones78b1acd2014-07-15 15:33:07 -07001779 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1780
Geoff Lang64f23f62014-09-10 14:40:12 -04001781 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1782 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001783 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001784 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001785 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001786
1787 // Ensure we don't overwrite our newly initialized data
1788 mImageArray[level]->markClean();
1789
1790 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791 }
1792
1793 if (!fastUnpacked)
1794 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001795 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001796 if (error.isError())
1797 {
1798 return error;
1799 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001800 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001801
1802 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001803}
1804
Geoff Langb5348332014-09-02 13:16:34 -04001805gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1806 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001807 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001808{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001809 ASSERT(target == GL_TEXTURE_3D);
1810
Brandon Jones78b1acd2014-07-15 15:33:07 -07001811 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1812 redefineImage(level, format, width, height, depth);
1813
Jamie Madillc751d1e2014-10-21 17:46:29 -04001814 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815}
1816
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001817gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1818 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1819 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001820{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001821 ASSERT(target == GL_TEXTURE_3D);
1822
Brandon Jones78b1acd2014-07-15 15:33:07 -07001823 bool fastUnpacked = false;
1824
Jamie Madillac7579c2014-09-17 16:59:33 -04001825 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1826
Brandon Jones78b1acd2014-07-15 15:33:07 -07001827 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1828 if (isFastUnpackable(unpack, getInternalFormat(level)))
1829 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001830 RenderTarget *destRenderTarget = NULL;
1831 gl::Error error = getRenderTarget(index, &destRenderTarget);
1832 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001833 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001834 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001835 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001836
1837 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1838 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1839 if (error.isError())
1840 {
1841 return error;
1842 }
1843
1844 // Ensure we don't overwrite our newly initialized data
1845 mImageArray[level]->markClean();
1846
1847 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848 }
1849
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001850 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001851 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001852 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1853 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001855
1856 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001857}
1858
Geoff Langb5348332014-09-02 13:16:34 -04001859gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1860 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001861 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001862{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001863 ASSERT(target == GL_TEXTURE_3D);
1864
Geoff Langb5348332014-09-02 13:16:34 -04001865 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001866 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001867 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001868 {
Geoff Langb5348332014-09-02 13:16:34 -04001869 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001870 }
Geoff Langb5348332014-09-02 13:16:34 -04001871
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001872 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1873 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1874 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001875}
1876
Geoff Langef7b0162014-09-04 13:29:23 -04001877gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1878 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001879{
1880 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001881 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001882}
1883
Geoff Langef7b0162014-09-04 13:29:23 -04001884gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1885 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001886{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001887 ASSERT(target == GL_TEXTURE_3D);
1888
Jamie Madill82bf0c52014-10-03 11:50:53 -04001889 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001890 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001891
Jamie Madille76bdda2014-10-20 17:13:52 -04001892 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001893 {
Geoff Langef7b0162014-09-04 13:29:23 -04001894 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1895 if (error.isError())
1896 {
1897 return error;
1898 }
1899
Brandon Jones78b1acd2014-07-15 15:33:07 -07001900 mDirtyImages = true;
1901 }
1902 else
1903 {
Geoff Langef7b0162014-09-04 13:29:23 -04001904 gl::Error error = ensureRenderTarget();
1905 if (error.isError())
1906 {
1907 return error;
1908 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909
1910 if (isValidLevel(level))
1911 {
Geoff Langef7b0162014-09-04 13:29:23 -04001912 error = updateStorageLevel(level);
1913 if (error.isError())
1914 {
1915 return error;
1916 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917
Geoff Langef7b0162014-09-04 13:29:23 -04001918 error = mRenderer->copyImage3D(source, sourceRect,
1919 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1920 xoffset, yoffset, zoffset, mTexStorage, level);
1921 if (error.isError())
1922 {
1923 return error;
1924 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001925 }
1926 }
Geoff Langef7b0162014-09-04 13:29:23 -04001927
1928 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001929}
1930
Geoff Lang1f8532b2014-09-05 09:46:13 -04001931gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001932{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001933 ASSERT(target == GL_TEXTURE_3D);
1934
Brandon Jones78b1acd2014-07-15 15:33:07 -07001935 for (int level = 0; level < levels; level++)
1936 {
1937 GLsizei levelWidth = std::max(1, width >> level);
1938 GLsizei levelHeight = std::max(1, height >> level);
1939 GLsizei levelDepth = std::max(1, depth >> level);
1940 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1941 }
1942
1943 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1944 {
1945 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1946 }
1947
Geoff Lang1f8532b2014-09-05 09:46:13 -04001948 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001949 bool renderTarget = IsRenderTargetUsage(mUsage);
1950 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001951
1952 gl::Error error = setCompleteTexStorage(storage);
1953 if (error.isError())
1954 {
1955 SafeDelete(storage);
1956 return error;
1957 }
1958
1959 mImmutable = true;
1960
1961 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001962}
1963
Brandon Jones6053a522014-07-25 16:22:09 -07001964void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001965{
Brandon Jones6053a522014-07-25 16:22:09 -07001966 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001967}
1968
Brandon Jones6053a522014-07-25 16:22:09 -07001969void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001970{
Brandon Jones6053a522014-07-25 16:22:09 -07001971 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001972}
1973
Brandon Jones6053a522014-07-25 16:22:09 -07001974
Jamie Madill4aa79e12014-09-29 10:46:14 -04001975void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001976{
1977 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1978 int levelCount = mipLevels();
1979 for (int level = 1; level < levelCount; level++)
1980 {
1981 redefineImage(level, getBaseLevelInternalFormat(),
1982 std::max(getBaseLevelWidth() >> level, 1),
1983 std::max(getBaseLevelHeight() >> level, 1),
1984 std::max(getBaseLevelDepth() >> level, 1));
1985 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001986}
1987
Jamie Madillac7579c2014-09-17 16:59:33 -04001988unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001989{
Geoff Langef7b0162014-09-04 13:29:23 -04001990 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001991}
1992
Geoff Lang64f23f62014-09-10 14:40:12 -04001993gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001994{
1995 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001996 gl::Error error = ensureRenderTarget();
1997 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001998 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001999 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002000 }
2001
Jamie Madillac7579c2014-09-17 16:59:33 -04002002 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002003 {
Geoff Langef7b0162014-09-04 13:29:23 -04002004 error = updateStorage();
2005 if (error.isError())
2006 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002007 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002008 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002009 }
2010 else
2011 {
Geoff Langef7b0162014-09-04 13:29:23 -04002012 error = updateStorageLevel(index.mipIndex);
2013 if (error.isError())
2014 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002015 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002016 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002017 }
2018
Geoff Lang64f23f62014-09-10 14:40:12 -04002019 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020}
2021
Geoff Langef7b0162014-09-04 13:29:23 -04002022gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002023{
2024 // Only initialize the first time this texture is used as a render target or shader resource
2025 if (mTexStorage)
2026 {
Geoff Langef7b0162014-09-04 13:29:23 -04002027 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002028 }
2029
2030 // do not attempt to create storage for nonexistant data
2031 if (!isLevelComplete(0))
2032 {
Geoff Langef7b0162014-09-04 13:29:23 -04002033 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002034 }
2035
2036 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2037
Jamie Madill30d6c252014-11-13 10:03:33 -05002038 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002039 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2040 if (error.isError())
2041 {
2042 return error;
2043 }
2044
2045 error = setCompleteTexStorage(storage);
2046 if (error.isError())
2047 {
2048 SafeDelete(storage);
2049 return error;
2050 }
2051
Brandon Jones78b1acd2014-07-15 15:33:07 -07002052 ASSERT(mTexStorage);
2053
2054 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002055 error = updateStorage();
2056 if (error.isError())
2057 {
2058 return error;
2059 }
2060
2061 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062}
2063
Geoff Langef7b0162014-09-04 13:29:23 -04002064gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002065{
2066 GLsizei width = getBaseLevelWidth();
2067 GLsizei height = getBaseLevelHeight();
2068 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002069 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002070
2071 ASSERT(width > 0 && height > 0 && depth > 0);
2072
2073 // use existing storage level count, when previously specified by TexStorage*D
2074 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2075
Geoff Langef7b0162014-09-04 13:29:23 -04002076 // TODO: Verify creation of the storage succeeded
2077 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2078
2079 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002080}
2081
Geoff Langef7b0162014-09-04 13:29:23 -04002082gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002083{
2084 SafeDelete(mTexStorage);
2085 mTexStorage = newCompleteTexStorage;
2086 mDirtyImages = true;
2087
2088 // We do not support managed 3D storage, as that is D3D9/ES2-only
2089 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002090
2091 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002092}
2093
Geoff Langef7b0162014-09-04 13:29:23 -04002094gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002095{
2096 ASSERT(mTexStorage != NULL);
2097 GLint storageLevels = mTexStorage->getLevelCount();
2098 for (int level = 0; level < storageLevels; level++)
2099 {
2100 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2101 {
Geoff Langef7b0162014-09-04 13:29:23 -04002102 gl::Error error = updateStorageLevel(level);
2103 if (error.isError())
2104 {
2105 return error;
2106 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002107 }
2108 }
Geoff Langef7b0162014-09-04 13:29:23 -04002109
2110 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002111}
2112
Brandon Jones78b1acd2014-07-15 15:33:07 -07002113bool TextureD3D_3D::isValidLevel(int level) const
2114{
2115 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2116}
2117
2118bool TextureD3D_3D::isLevelComplete(int level) const
2119{
2120 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2121
2122 if (isImmutable())
2123 {
2124 return true;
2125 }
2126
2127 GLsizei width = getBaseLevelWidth();
2128 GLsizei height = getBaseLevelHeight();
2129 GLsizei depth = getBaseLevelDepth();
2130
2131 if (width <= 0 || height <= 0 || depth <= 0)
2132 {
2133 return false;
2134 }
2135
2136 if (level == 0)
2137 {
2138 return true;
2139 }
2140
2141 ImageD3D *levelImage = mImageArray[level];
2142
2143 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2144 {
2145 return false;
2146 }
2147
2148 if (levelImage->getWidth() != std::max(1, width >> level))
2149 {
2150 return false;
2151 }
2152
2153 if (levelImage->getHeight() != std::max(1, height >> level))
2154 {
2155 return false;
2156 }
2157
2158 if (levelImage->getDepth() != std::max(1, depth >> level))
2159 {
2160 return false;
2161 }
2162
2163 return true;
2164}
2165
Jamie Madille76bdda2014-10-20 17:13:52 -04002166bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2167{
2168 return isLevelComplete(index.mipIndex);
2169}
2170
Geoff Langef7b0162014-09-04 13:29:23 -04002171gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002172{
2173 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2174 ASSERT(isLevelComplete(level));
2175
2176 if (mImageArray[level]->isDirty())
2177 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002178 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2179 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002180 gl::Error error = commitRegion(index, region);
2181 if (error.isError())
2182 {
2183 return error;
2184 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002185 }
Geoff Langef7b0162014-09-04 13:29:23 -04002186
2187 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002188}
2189
2190void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2191{
2192 // If there currently is a corresponding storage texture image, it has these parameters
2193 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2194 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2195 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2196 const GLenum storageFormat = getBaseLevelInternalFormat();
2197
2198 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2199
2200 if (mTexStorage)
2201 {
2202 const int storageLevels = mTexStorage->getLevelCount();
2203
2204 if ((level >= storageLevels && storageLevels != 0) ||
2205 width != storageWidth ||
2206 height != storageHeight ||
2207 depth != storageDepth ||
2208 internalformat != storageFormat) // Discard mismatched storage
2209 {
2210 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2211 {
2212 mImageArray[i]->markDirty();
2213 }
2214
2215 SafeDelete(mTexStorage);
2216 mDirtyImages = true;
2217 }
2218 }
2219}
2220
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002221gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2222{
2223 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2224 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2225}
Brandon Jones142ec422014-07-16 10:31:30 -07002226
Jamie Madillcb83dc12014-09-29 10:46:12 -04002227gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2228{
2229 // The "layer" here does not apply to 3D images. We use one Image per mip.
2230 return gl::ImageIndex::Make3D(mip);
2231}
2232
Jamie Madill710e5772014-10-20 17:13:53 -04002233bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2234{
2235 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2236 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2237}
2238
Jamie Madill93e13fb2014-11-06 15:27:25 -05002239TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002240 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002241{
2242 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2243 {
2244 mLayerCounts[level] = 0;
2245 mImageArray[level] = NULL;
2246 }
2247}
2248
2249TextureD3D_2DArray::~TextureD3D_2DArray()
2250{
Austin Kinross69822602014-08-12 15:51:37 -07002251 // Delete the Images before the TextureStorage.
2252 // Images might be relying on the TextureStorage for some of their data.
2253 // 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 -07002254 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002255 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002256}
2257
Brandon Jones142ec422014-07-16 10:31:30 -07002258Image *TextureD3D_2DArray::getImage(int level, int layer) const
2259{
2260 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002261 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2262 layer < mLayerCounts[level]);
2263 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002264}
2265
Jamie Madillfeda4d22014-09-17 13:03:29 -04002266Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2267{
2268 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002269 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2270 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002271 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002272 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002273}
2274
Brandon Jones142ec422014-07-16 10:31:30 -07002275GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2276{
2277 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2278 return mLayerCounts[level];
2279}
2280
Brandon Jones142ec422014-07-16 10:31:30 -07002281GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2282{
2283 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2284}
2285
2286GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2287{
2288 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2289}
2290
Brandon Jones142ec422014-07-16 10:31:30 -07002291GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2292{
2293 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2294}
2295
2296bool TextureD3D_2DArray::isDepth(GLint level) const
2297{
Geoff Lang5d601382014-07-22 15:14:06 -04002298 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002299}
2300
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002301gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2302 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2303 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002304{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002305 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2306
Geoff Lang5d601382014-07-22 15:14:06 -04002307 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2308
Brandon Jones142ec422014-07-16 10:31:30 -07002309 redefineImage(level, sizedInternalFormat, width, height, depth);
2310
Geoff Lang5d601382014-07-22 15:14:06 -04002311 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2312 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002313
2314 for (int i = 0; i < depth; i++)
2315 {
2316 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002317 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2318 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002319 if (error.isError())
2320 {
2321 return error;
2322 }
Brandon Jones142ec422014-07-16 10:31:30 -07002323 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002324
2325 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002326}
2327
Geoff Langb5348332014-09-02 13:16:34 -04002328gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2329 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002330 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002331{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002332 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2333
Brandon Jones142ec422014-07-16 10:31:30 -07002334 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2335 redefineImage(level, format, width, height, depth);
2336
Geoff Lang5d601382014-07-22 15:14:06 -04002337 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2338 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002339
2340 for (int i = 0; i < depth; i++)
2341 {
2342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002343 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002344 if (error.isError())
2345 {
2346 return error;
2347 }
Brandon Jones142ec422014-07-16 10:31:30 -07002348 }
Geoff Langb5348332014-09-02 13:16:34 -04002349
2350 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002351}
2352
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002353gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2354 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2355 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002356{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002357 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2358
Geoff Lang5d601382014-07-22 15:14:06 -04002359 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2360 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002361
2362 for (int i = 0; i < depth; i++)
2363 {
2364 int layer = zoffset + i;
2365 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2366
Jamie Madillfeda4d22014-09-17 13:03:29 -04002367 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madillf8fccb32014-11-12 15:05:26 -05002368 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
Jamie Madille6b6da02014-10-02 11:03:14 -04002369 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002370 if (error.isError())
2371 {
2372 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002373 }
2374 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002375
2376 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002377}
2378
Geoff Langb5348332014-09-02 13:16:34 -04002379gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2380 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002381 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002382{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002383 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2384
Geoff Lang5d601382014-07-22 15:14:06 -04002385 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2386 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002387
2388 for (int i = 0; i < depth; i++)
2389 {
2390 int layer = zoffset + i;
2391 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2392
Jamie Madillc751d1e2014-10-21 17:46:29 -04002393 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 -04002394 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002395 {
Geoff Langb5348332014-09-02 13:16:34 -04002396 return error;
2397 }
2398
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002399 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2400 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2401 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002402 if (error.isError())
2403 {
2404 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002405 }
2406 }
Geoff Langb5348332014-09-02 13:16:34 -04002407
2408 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002409}
2410
Geoff Langef7b0162014-09-04 13:29:23 -04002411gl::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 -07002412{
2413 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002414 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002415}
2416
Geoff Langef7b0162014-09-04 13:29:23 -04002417gl::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 -07002418{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002419 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2420
Jamie Madill82bf0c52014-10-03 11:50:53 -04002421 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002422 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002423
Jamie Madille76bdda2014-10-20 17:13:52 -04002424 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002425 {
Geoff Langef7b0162014-09-04 13:29:23 -04002426 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2427 if (error.isError())
2428 {
2429 return error;
2430 }
2431
Brandon Jones142ec422014-07-16 10:31:30 -07002432 mDirtyImages = true;
2433 }
2434 else
2435 {
Geoff Langef7b0162014-09-04 13:29:23 -04002436 gl::Error error = ensureRenderTarget();
2437 if (error.isError())
2438 {
2439 return error;
2440 }
Brandon Jones142ec422014-07-16 10:31:30 -07002441
2442 if (isValidLevel(level))
2443 {
Geoff Langef7b0162014-09-04 13:29:23 -04002444 error = updateStorageLevel(level);
2445 if (error.isError())
2446 {
2447 return error;
2448 }
Brandon Jones142ec422014-07-16 10:31:30 -07002449
Geoff Langef7b0162014-09-04 13:29:23 -04002450 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2451 xoffset, yoffset, zoffset, mTexStorage, level);
2452 if (error.isError())
2453 {
2454 return error;
2455 }
Brandon Jones142ec422014-07-16 10:31:30 -07002456 }
2457 }
Geoff Langef7b0162014-09-04 13:29:23 -04002458 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002459}
2460
Geoff Lang1f8532b2014-09-05 09:46:13 -04002461gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002462{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002463 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2464
Brandon Jones142ec422014-07-16 10:31:30 -07002465 deleteImages();
2466
2467 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2468 {
2469 GLsizei levelWidth = std::max(1, width >> level);
2470 GLsizei levelHeight = std::max(1, height >> level);
2471
2472 mLayerCounts[level] = (level < levels ? depth : 0);
2473
2474 if (mLayerCounts[level] > 0)
2475 {
2476 // Create new images for this level
2477 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2478
2479 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2480 {
2481 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2482 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2483 levelHeight, 1, true);
2484 }
2485 }
2486 }
2487
Geoff Lang1f8532b2014-09-05 09:46:13 -04002488 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002489 bool renderTarget = IsRenderTargetUsage(mUsage);
2490 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002491
2492 gl::Error error = setCompleteTexStorage(storage);
2493 if (error.isError())
2494 {
2495 SafeDelete(storage);
2496 return error;
2497 }
2498
2499 mImmutable = true;
2500
2501 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002502}
2503
Brandon Jones6053a522014-07-25 16:22:09 -07002504void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002505{
Brandon Jones6053a522014-07-25 16:22:09 -07002506 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002507}
2508
Brandon Jones6053a522014-07-25 16:22:09 -07002509void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002510{
Brandon Jones6053a522014-07-25 16:22:09 -07002511 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002512}
2513
Brandon Jones6053a522014-07-25 16:22:09 -07002514
Jamie Madill4aa79e12014-09-29 10:46:14 -04002515void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002516{
2517 int baseWidth = getBaseLevelWidth();
2518 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002519 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002520 GLenum baseFormat = getBaseLevelInternalFormat();
2521
2522 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2523 int levelCount = mipLevels();
2524 for (int level = 1; level < levelCount; level++)
2525 {
2526 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2527 }
Brandon Jones142ec422014-07-16 10:31:30 -07002528}
2529
Jamie Madillac7579c2014-09-17 16:59:33 -04002530unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002531{
Geoff Langef7b0162014-09-04 13:29:23 -04002532 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002533}
2534
Geoff Lang64f23f62014-09-10 14:40:12 -04002535gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002536{
2537 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002538 gl::Error error = ensureRenderTarget();
2539 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002540 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002541 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002542 }
2543
Geoff Langef7b0162014-09-04 13:29:23 -04002544 error = updateStorageLevel(index.mipIndex);
2545 if (error.isError())
2546 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002547 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002548 }
2549
Geoff Lang64f23f62014-09-10 14:40:12 -04002550 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002551}
2552
Geoff Langef7b0162014-09-04 13:29:23 -04002553gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002554{
2555 // Only initialize the first time this texture is used as a render target or shader resource
2556 if (mTexStorage)
2557 {
Geoff Langef7b0162014-09-04 13:29:23 -04002558 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002559 }
2560
2561 // do not attempt to create storage for nonexistant data
2562 if (!isLevelComplete(0))
2563 {
Geoff Langef7b0162014-09-04 13:29:23 -04002564 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002565 }
2566
2567 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2568
Geoff Langef7b0162014-09-04 13:29:23 -04002569 TextureStorage *storage = NULL;
2570 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2571 if (error.isError())
2572 {
2573 return error;
2574 }
2575
2576 error = setCompleteTexStorage(storage);
2577 if (error.isError())
2578 {
2579 SafeDelete(storage);
2580 return error;
2581 }
2582
Brandon Jones142ec422014-07-16 10:31:30 -07002583 ASSERT(mTexStorage);
2584
2585 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002586 error = updateStorage();
2587 if (error.isError())
2588 {
2589 return error;
2590 }
2591
2592 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002593}
2594
Geoff Langef7b0162014-09-04 13:29:23 -04002595gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002596{
2597 GLsizei width = getBaseLevelWidth();
2598 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002599 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002600 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002601
2602 ASSERT(width > 0 && height > 0 && depth > 0);
2603
2604 // use existing storage level count, when previously specified by TexStorage*D
2605 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2606
Geoff Langef7b0162014-09-04 13:29:23 -04002607 // TODO(geofflang): Verify storage creation succeeds
2608 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2609
2610 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002611}
2612
Geoff Langef7b0162014-09-04 13:29:23 -04002613gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002614{
2615 SafeDelete(mTexStorage);
2616 mTexStorage = newCompleteTexStorage;
2617 mDirtyImages = true;
2618
2619 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2620 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002621
2622 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002623}
2624
Geoff Langef7b0162014-09-04 13:29:23 -04002625gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002626{
2627 ASSERT(mTexStorage != NULL);
2628 GLint storageLevels = mTexStorage->getLevelCount();
2629 for (int level = 0; level < storageLevels; level++)
2630 {
2631 if (isLevelComplete(level))
2632 {
Geoff Langef7b0162014-09-04 13:29:23 -04002633 gl::Error error = updateStorageLevel(level);
2634 if (error.isError())
2635 {
2636 return error;
2637 }
Brandon Jones142ec422014-07-16 10:31:30 -07002638 }
2639 }
Geoff Langef7b0162014-09-04 13:29:23 -04002640
2641 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002642}
2643
Brandon Jones142ec422014-07-16 10:31:30 -07002644bool TextureD3D_2DArray::isValidLevel(int level) const
2645{
2646 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2647}
2648
2649bool TextureD3D_2DArray::isLevelComplete(int level) const
2650{
2651 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2652
2653 if (isImmutable())
2654 {
2655 return true;
2656 }
2657
2658 GLsizei width = getBaseLevelWidth();
2659 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002660 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002661
2662 if (width <= 0 || height <= 0 || layers <= 0)
2663 {
2664 return false;
2665 }
2666
2667 if (level == 0)
2668 {
2669 return true;
2670 }
2671
2672 if (getInternalFormat(level) != getInternalFormat(0))
2673 {
2674 return false;
2675 }
2676
2677 if (getWidth(level) != std::max(1, width >> level))
2678 {
2679 return false;
2680 }
2681
2682 if (getHeight(level) != std::max(1, height >> level))
2683 {
2684 return false;
2685 }
2686
Jamie Madill3269bcb2014-09-30 16:33:52 -04002687 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002688 {
2689 return false;
2690 }
2691
2692 return true;
2693}
2694
Jamie Madille76bdda2014-10-20 17:13:52 -04002695bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2696{
2697 return isLevelComplete(index.mipIndex);
2698}
2699
Geoff Langef7b0162014-09-04 13:29:23 -04002700gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002701{
2702 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2703 ASSERT(isLevelComplete(level));
2704
2705 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2706 {
2707 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2708 if (mImageArray[level][layer]->isDirty())
2709 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002710 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2711 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002712 gl::Error error = commitRegion(index, region);
2713 if (error.isError())
2714 {
2715 return error;
2716 }
Brandon Jones142ec422014-07-16 10:31:30 -07002717 }
2718 }
Geoff Langef7b0162014-09-04 13:29:23 -04002719
2720 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002721}
2722
2723void TextureD3D_2DArray::deleteImages()
2724{
2725 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2726 {
2727 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2728 {
2729 delete mImageArray[level][layer];
2730 }
2731 delete[] mImageArray[level];
2732 mImageArray[level] = NULL;
2733 mLayerCounts[level] = 0;
2734 }
2735}
2736
2737void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2738{
2739 // If there currently is a corresponding storage texture image, it has these parameters
2740 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2741 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002742 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002743 const GLenum storageFormat = getBaseLevelInternalFormat();
2744
2745 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2746 {
2747 delete mImageArray[level][layer];
2748 }
2749 delete[] mImageArray[level];
2750 mImageArray[level] = NULL;
2751 mLayerCounts[level] = depth;
2752
2753 if (depth > 0)
2754 {
2755 mImageArray[level] = new ImageD3D*[depth]();
2756
2757 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2758 {
2759 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2760 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2761 }
2762 }
2763
2764 if (mTexStorage)
2765 {
2766 const int storageLevels = mTexStorage->getLevelCount();
2767
2768 if ((level >= storageLevels && storageLevels != 0) ||
2769 width != storageWidth ||
2770 height != storageHeight ||
2771 depth != storageDepth ||
2772 internalformat != storageFormat) // Discard mismatched storage
2773 {
2774 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2775 {
2776 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2777 {
2778 mImageArray[level][layer]->markDirty();
2779 }
2780 }
2781
2782 delete mTexStorage;
2783 mTexStorage = NULL;
2784 mDirtyImages = true;
2785 }
2786 }
2787}
2788
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002789gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2790{
2791 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2792}
2793
Jamie Madillcb83dc12014-09-29 10:46:12 -04002794gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2795{
2796 return gl::ImageIndex::Make2DArray(mip, layer);
2797}
2798
Jamie Madill710e5772014-10-20 17:13:53 -04002799bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2800{
2801 // Check for having a storage and the right type of index
2802 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2803 {
2804 return false;
2805 }
2806
2807 // Check the mip index
2808 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2809 {
2810 return false;
2811 }
2812
2813 // Check the layer index
2814 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2815}
2816
Brandon Jones78b1acd2014-07-15 15:33:07 -07002817}