blob: 56f3a4561c7a0adeeacff6920575da83ab79109b [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 Madill93e13fb2014-11-06 15:27:25 -05009#include "libGLESv2/Buffer.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070010#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070011#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/formatutils.h"
13#include "libGLESv2/renderer/BufferImpl.h"
14#include "libGLESv2/renderer/RenderTarget.h"
Jamie Madill93e13fb2014-11-06 15:27:25 -050015#include "libGLESv2/renderer/d3d/BufferD3D.h"
16#include "libGLESv2/renderer/d3d/TextureD3D.h"
17#include "libGLESv2/renderer/d3d/TextureStorage.h"
18#include "libGLESv2/renderer/d3d/ImageD3D.h"
19#include "libGLESv2/renderer/d3d/RendererD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.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
850 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700851
852 mDirtyImages = true;
853}
854
855void TextureD3D_2D::releaseTexImage()
856{
857 if (mTexStorage)
858 {
859 SafeDelete(mTexStorage);
860 }
861
862 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
863 {
864 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
865 }
866}
867
Jamie Madill4aa79e12014-09-29 10:46:14 -0400868void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700870 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700871 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700872 for (int level = 1; level < levelCount; level++)
873 {
874 redefineImage(level, getBaseLevelInternalFormat(),
875 std::max(getBaseLevelWidth() >> level, 1),
876 std::max(getBaseLevelHeight() >> level, 1));
877 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700878}
879
Jamie Madillac7579c2014-09-17 16:59:33 -0400880unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700881{
Jamie Madillac7579c2014-09-17 16:59:33 -0400882 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400883 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884}
885
Geoff Lang64f23f62014-09-10 14:40:12 -0400886gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700887{
Jamie Madillac7579c2014-09-17 16:59:33 -0400888 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700889
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700890 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400891 gl::Error error = ensureRenderTarget();
892 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700893 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400894 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700895 }
896
Geoff Langef7b0162014-09-04 13:29:23 -0400897 error = updateStorageLevel(index.mipIndex);
898 if (error.isError())
899 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400900 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400901 }
902
Geoff Lang64f23f62014-09-10 14:40:12 -0400903 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700904}
905
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700906bool TextureD3D_2D::isValidLevel(int level) const
907{
908 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
909}
910
911bool TextureD3D_2D::isLevelComplete(int level) const
912{
913 if (isImmutable())
914 {
915 return true;
916 }
917
Brandon Jones78b1acd2014-07-15 15:33:07 -0700918 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919
920 GLsizei width = baseImage->getWidth();
921 GLsizei height = baseImage->getHeight();
922
923 if (width <= 0 || height <= 0)
924 {
925 return false;
926 }
927
928 // The base image level is complete if the width and height are positive
929 if (level == 0)
930 {
931 return true;
932 }
933
934 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700935 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700936
937 if (image->getInternalFormat() != baseImage->getInternalFormat())
938 {
939 return false;
940 }
941
942 if (image->getWidth() != std::max(1, width >> level))
943 {
944 return false;
945 }
946
947 if (image->getHeight() != std::max(1, height >> level))
948 {
949 return false;
950 }
951
952 return true;
953}
954
Jamie Madille76bdda2014-10-20 17:13:52 -0400955bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
956{
957 return isLevelComplete(index.mipIndex);
958}
959
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700960// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400961gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700962{
963 // Only initialize the first time this texture is used as a render target or shader resource
964 if (mTexStorage)
965 {
Geoff Langef7b0162014-09-04 13:29:23 -0400966 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700967 }
968
969 // do not attempt to create storage for nonexistant data
970 if (!isLevelComplete(0))
971 {
Geoff Langef7b0162014-09-04 13:29:23 -0400972 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700973 }
974
975 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
976
Geoff Langef7b0162014-09-04 13:29:23 -0400977 TextureStorage *storage = NULL;
978 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
979 if (error.isError())
980 {
981 return error;
982 }
983
984 error = setCompleteTexStorage(storage);
985 if (error.isError())
986 {
987 SafeDelete(storage);
988 return error;
989 }
990
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700991 ASSERT(mTexStorage);
992
993 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400994 error = updateStorage();
995 if (error.isError())
996 {
997 return error;
998 }
999
1000 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001001}
1002
Geoff Langef7b0162014-09-04 13:29:23 -04001003gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001004{
1005 GLsizei width = getBaseLevelWidth();
1006 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001007 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001008
1009 ASSERT(width > 0 && height > 0);
1010
1011 // use existing storage level count, when previously specified by TexStorage*D
1012 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1013
Geoff Langef7b0162014-09-04 13:29:23 -04001014 // TODO(geofflang): Determine if the texture creation succeeded
1015 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
1016
1017 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001018}
1019
Geoff Langef7b0162014-09-04 13:29:23 -04001020gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001021{
Geoff Langef7b0162014-09-04 13:29:23 -04001022 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001023 {
Geoff Langef7b0162014-09-04 13:29:23 -04001024 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001025 {
Geoff Langef7b0162014-09-04 13:29:23 -04001026 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1027 if (error.isError())
1028 {
1029 return error;
1030 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001031 }
1032 }
1033
Geoff Langef7b0162014-09-04 13:29:23 -04001034 SafeDelete(mTexStorage);
1035 mTexStorage = newCompleteTexStorage;
1036
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001037 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001038
1039 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001040}
1041
Geoff Langef7b0162014-09-04 13:29:23 -04001042gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001043{
1044 ASSERT(mTexStorage != NULL);
1045 GLint storageLevels = mTexStorage->getLevelCount();
1046 for (int level = 0; level < storageLevels; level++)
1047 {
1048 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1049 {
Geoff Langef7b0162014-09-04 13:29:23 -04001050 gl::Error error = updateStorageLevel(level);
1051 if (error.isError())
1052 {
1053 return error;
1054 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001055 }
1056 }
Geoff Langef7b0162014-09-04 13:29:23 -04001057
1058 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001059}
1060
Geoff Langef7b0162014-09-04 13:29:23 -04001061gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001062{
1063 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1064 ASSERT(isLevelComplete(level));
1065
1066 if (mImageArray[level]->isDirty())
1067 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001068 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1069 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001070 gl::Error error = commitRegion(index, region);
1071 if (error.isError())
1072 {
1073 return error;
1074 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001075 }
Geoff Langef7b0162014-09-04 13:29:23 -04001076
1077 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001078}
1079
1080void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1081{
1082 // If there currently is a corresponding storage texture image, it has these parameters
1083 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1084 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1085 const GLenum storageFormat = getBaseLevelInternalFormat();
1086
1087 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1088
1089 if (mTexStorage)
1090 {
1091 const int storageLevels = mTexStorage->getLevelCount();
1092
1093 if ((level >= storageLevels && storageLevels != 0) ||
1094 width != storageWidth ||
1095 height != storageHeight ||
1096 internalformat != storageFormat) // Discard mismatched storage
1097 {
1098 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1099 {
1100 mImageArray[i]->markDirty();
1101 }
1102
1103 SafeDelete(mTexStorage);
1104 mDirtyImages = true;
1105 }
1106 }
1107}
1108
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001109gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1110{
1111 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1112}
Brandon Jones0511e802014-07-14 16:27:26 -07001113
Jamie Madillcb83dc12014-09-29 10:46:12 -04001114gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1115{
1116 // "layer" does not apply to 2D Textures.
1117 return gl::ImageIndex::Make2D(mip);
1118}
1119
Jamie Madill710e5772014-10-20 17:13:53 -04001120bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1121{
1122 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1123 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1124}
1125
Jamie Madill93e13fb2014-11-06 15:27:25 -05001126TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001127 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001128{
1129 for (int i = 0; i < 6; i++)
1130 {
1131 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1132 {
1133 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1134 }
1135 }
1136}
1137
1138TextureD3D_Cube::~TextureD3D_Cube()
1139{
Austin Kinross69822602014-08-12 15:51:37 -07001140 // Delete the Images before the TextureStorage.
1141 // Images might be relying on the TextureStorage for some of their data.
1142 // 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 -07001143 for (int i = 0; i < 6; i++)
1144 {
1145 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1146 {
1147 SafeDelete(mImageArray[i][j]);
1148 }
1149 }
Austin Kinross69822602014-08-12 15:51:37 -07001150
1151 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001152}
1153
Brandon Jonescef06ff2014-08-05 13:27:48 -07001154Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001155{
1156 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001157 ASSERT(layer < 6);
1158 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001159}
1160
Jamie Madillfeda4d22014-09-17 13:03:29 -04001161Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1162{
1163 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1164 ASSERT(index.layerIndex < 6);
1165 return mImageArray[index.layerIndex][index.mipIndex];
1166}
1167
Brandon Jonescef06ff2014-08-05 13:27:48 -07001168GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001169{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001170 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1171 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001172}
1173
Brandon Jonescef06ff2014-08-05 13:27:48 -07001174GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001175{
1176 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001177 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001178 else
1179 return GL_NONE;
1180}
1181
Brandon Jonescef06ff2014-08-05 13:27:48 -07001182bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001183{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001184 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001185}
1186
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001187gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1188 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1189 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001190{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001191 ASSERT(depth == 1);
1192
Geoff Lang5d601382014-07-22 15:14:06 -04001193 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001194 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001195
Jamie Madillba6bc952014-10-06 10:56:22 -04001196 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001197
Jamie Madillba6bc952014-10-06 10:56:22 -04001198 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001199}
1200
Geoff Langb5348332014-09-02 13:16:34 -04001201gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1202 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001203 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001204{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001205 ASSERT(depth == 1);
1206
Brandon Jones0511e802014-07-14 16:27:26 -07001207 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001208 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1209
Brandon Jones0511e802014-07-14 16:27:26 -07001210 redefineImage(faceIndex, level, format, width, height);
1211
Jamie Madillc751d1e2014-10-21 17:46:29 -04001212 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001213}
1214
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001215gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1216 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1217 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001218{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001219 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001220 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001221 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001222}
1223
Geoff Langb5348332014-09-02 13:16:34 -04001224gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1225 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001226 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001227{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001228 ASSERT(depth == 1 && zoffset == 0);
1229
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001230 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001231
Jamie Madillc751d1e2014-10-21 17:46:29 -04001232 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 -04001233 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001234 {
Geoff Langb5348332014-09-02 13:16:34 -04001235 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001236 }
Geoff Langb5348332014-09-02 13:16:34 -04001237
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001238 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1239 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001240}
1241
Geoff Langef7b0162014-09-04 13:29:23 -04001242gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1243 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001244{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001245 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001246 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1247
Brandon Jones0511e802014-07-14 16:27:26 -07001248 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1249
Jamie Madill82bf0c52014-10-03 11:50:53 -04001250 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001251 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001252
Jamie Madille76bdda2014-10-20 17:13:52 -04001253 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001254 {
Geoff Langef7b0162014-09-04 13:29:23 -04001255 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1256 if (error.isError())
1257 {
1258 return error;
1259 }
1260
Brandon Jones0511e802014-07-14 16:27:26 -07001261 mDirtyImages = true;
1262 }
1263 else
1264 {
Geoff Langef7b0162014-09-04 13:29:23 -04001265 gl::Error error = ensureRenderTarget();
1266 if (error.isError())
1267 {
1268 return error;
1269 }
1270
Brandon Jones0511e802014-07-14 16:27:26 -07001271 mImageArray[faceIndex][level]->markClean();
1272
1273 ASSERT(width == height);
1274
1275 if (width > 0 && isValidFaceLevel(faceIndex, level))
1276 {
Geoff Langef7b0162014-09-04 13:29:23 -04001277 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1278 if (error.isError())
1279 {
1280 return error;
1281 }
Brandon Jones0511e802014-07-14 16:27:26 -07001282 }
1283 }
Geoff Langef7b0162014-09-04 13:29:23 -04001284
1285 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001286}
1287
Geoff Langef7b0162014-09-04 13:29:23 -04001288gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1289 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001290{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001291 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001292
Jamie Madill82bf0c52014-10-03 11:50:53 -04001293 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001294 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001295
Jamie Madille76bdda2014-10-20 17:13:52 -04001296 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001297 {
Geoff Langef7b0162014-09-04 13:29:23 -04001298 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1299 if (error.isError())
1300 {
1301 return error;
1302 }
1303
Brandon Jones0511e802014-07-14 16:27:26 -07001304 mDirtyImages = true;
1305 }
1306 else
1307 {
Geoff Langef7b0162014-09-04 13:29:23 -04001308 gl::Error error = ensureRenderTarget();
1309 if (error.isError())
1310 {
1311 return error;
1312 }
Brandon Jones0511e802014-07-14 16:27:26 -07001313
1314 if (isValidFaceLevel(faceIndex, level))
1315 {
Geoff Langef7b0162014-09-04 13:29:23 -04001316 error = updateStorageFaceLevel(faceIndex, level);
1317 if (error.isError())
1318 {
1319 return error;
1320 }
Brandon Jones0511e802014-07-14 16:27:26 -07001321
Geoff Langef7b0162014-09-04 13:29:23 -04001322 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1323 xoffset, yoffset, mTexStorage, target, level);
1324 if (error.isError())
1325 {
1326 return error;
1327 }
Brandon Jones0511e802014-07-14 16:27:26 -07001328 }
1329 }
Geoff Langef7b0162014-09-04 13:29:23 -04001330
1331 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001332}
1333
Geoff Lang1f8532b2014-09-05 09:46:13 -04001334gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001335{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001336 ASSERT(width == height);
1337 ASSERT(depth == 1);
1338
Brandon Jones0511e802014-07-14 16:27:26 -07001339 for (int level = 0; level < levels; level++)
1340 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001341 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001342 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1343 {
1344 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1345 }
1346 }
1347
1348 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1349 {
1350 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1351 {
1352 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1353 }
1354 }
1355
Geoff Lang1f8532b2014-09-05 09:46:13 -04001356 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001357 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001358 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001359
1360 gl::Error error = setCompleteTexStorage(storage);
1361 if (error.isError())
1362 {
1363 SafeDelete(storage);
1364 return error;
1365 }
1366
1367 mImmutable = true;
1368
1369 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001370}
1371
Brandon Jones0511e802014-07-14 16:27:26 -07001372// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1373bool TextureD3D_Cube::isCubeComplete() const
1374{
1375 int baseWidth = getBaseLevelWidth();
1376 int baseHeight = getBaseLevelHeight();
1377 GLenum baseFormat = getBaseLevelInternalFormat();
1378
1379 if (baseWidth <= 0 || baseWidth != baseHeight)
1380 {
1381 return false;
1382 }
1383
1384 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1385 {
1386 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1387
1388 if (faceBaseImage.getWidth() != baseWidth ||
1389 faceBaseImage.getHeight() != baseHeight ||
1390 faceBaseImage.getInternalFormat() != baseFormat )
1391 {
1392 return false;
1393 }
1394 }
1395
1396 return true;
1397}
1398
Brandon Jones6053a522014-07-25 16:22:09 -07001399void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1400{
1401 UNREACHABLE();
1402}
1403
1404void TextureD3D_Cube::releaseTexImage()
1405{
1406 UNREACHABLE();
1407}
1408
1409
Jamie Madill4aa79e12014-09-29 10:46:14 -04001410void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001411{
1412 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1413 int levelCount = mipLevels();
1414 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1415 {
1416 for (int level = 1; level < levelCount; level++)
1417 {
1418 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1419 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1420 }
1421 }
Brandon Jones0511e802014-07-14 16:27:26 -07001422}
1423
Jamie Madillac7579c2014-09-17 16:59:33 -04001424unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001425{
Geoff Langef7b0162014-09-04 13:29:23 -04001426 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001427}
1428
Geoff Lang64f23f62014-09-10 14:40:12 -04001429gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001430{
Jamie Madillac7579c2014-09-17 16:59:33 -04001431 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001432
1433 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001434 gl::Error error = ensureRenderTarget();
1435 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001436 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001437 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001438 }
1439
Geoff Langef7b0162014-09-04 13:29:23 -04001440 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1441 if (error.isError())
1442 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001443 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001444 }
1445
Geoff Lang64f23f62014-09-10 14:40:12 -04001446 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001447}
1448
Geoff Langef7b0162014-09-04 13:29:23 -04001449gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001450{
1451 // Only initialize the first time this texture is used as a render target or shader resource
1452 if (mTexStorage)
1453 {
Geoff Langef7b0162014-09-04 13:29:23 -04001454 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001455 }
1456
1457 // do not attempt to create storage for nonexistant data
1458 if (!isFaceLevelComplete(0, 0))
1459 {
Geoff Langef7b0162014-09-04 13:29:23 -04001460 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001461 }
1462
1463 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1464
Geoff Langef7b0162014-09-04 13:29:23 -04001465 TextureStorage *storage = NULL;
1466 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1467 if (error.isError())
1468 {
1469 return error;
1470 }
1471
1472 error = setCompleteTexStorage(storage);
1473 if (error.isError())
1474 {
1475 SafeDelete(storage);
1476 return error;
1477 }
1478
Brandon Jones0511e802014-07-14 16:27:26 -07001479 ASSERT(mTexStorage);
1480
1481 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001482 error = updateStorage();
1483 if (error.isError())
1484 {
1485 return error;
1486 }
1487
1488 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001489}
1490
Geoff Langef7b0162014-09-04 13:29:23 -04001491gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001492{
1493 GLsizei size = getBaseLevelWidth();
1494
1495 ASSERT(size > 0);
1496
1497 // use existing storage level count, when previously specified by TexStorage*D
1498 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1499
Geoff Langef7b0162014-09-04 13:29:23 -04001500 // TODO (geofflang): detect if storage creation succeeded
1501 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1502
1503 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001504}
1505
Geoff Langef7b0162014-09-04 13:29:23 -04001506gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001507{
Geoff Langef7b0162014-09-04 13:29:23 -04001508 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001509 {
1510 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1511 {
Geoff Langef7b0162014-09-04 13:29:23 -04001512 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001513 {
Geoff Langef7b0162014-09-04 13:29:23 -04001514 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1515 if (error.isError())
1516 {
1517 return error;
1518 }
Brandon Jones0511e802014-07-14 16:27:26 -07001519 }
1520 }
1521 }
1522
Geoff Langef7b0162014-09-04 13:29:23 -04001523 SafeDelete(mTexStorage);
1524 mTexStorage = newCompleteTexStorage;
1525
Brandon Jones0511e802014-07-14 16:27:26 -07001526 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001527 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001528}
1529
Geoff Langef7b0162014-09-04 13:29:23 -04001530gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001531{
1532 ASSERT(mTexStorage != NULL);
1533 GLint storageLevels = mTexStorage->getLevelCount();
1534 for (int face = 0; face < 6; face++)
1535 {
1536 for (int level = 0; level < storageLevels; level++)
1537 {
1538 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1539 {
Geoff Langef7b0162014-09-04 13:29:23 -04001540 gl::Error error = updateStorageFaceLevel(face, level);
1541 if (error.isError())
1542 {
1543 return error;
1544 }
Brandon Jones0511e802014-07-14 16:27:26 -07001545 }
1546 }
1547 }
Geoff Langef7b0162014-09-04 13:29:23 -04001548
1549 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001550}
1551
Brandon Jones0511e802014-07-14 16:27:26 -07001552bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1553{
1554 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1555}
1556
Brandon Jones0511e802014-07-14 16:27:26 -07001557bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1558{
1559 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1560
1561 if (isImmutable())
1562 {
1563 return true;
1564 }
1565
1566 int baseSize = getBaseLevelWidth();
1567
1568 if (baseSize <= 0)
1569 {
1570 return false;
1571 }
1572
1573 // "isCubeComplete" checks for base level completeness and we must call that
1574 // to determine if any face at level 0 is complete. We omit that check here
1575 // to avoid re-checking cube-completeness for every face at level 0.
1576 if (level == 0)
1577 {
1578 return true;
1579 }
1580
1581 // Check that non-zero levels are consistent with the base level.
1582 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1583
1584 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1585 {
1586 return false;
1587 }
1588
1589 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1590 {
1591 return false;
1592 }
1593
1594 return true;
1595}
1596
Jamie Madille76bdda2014-10-20 17:13:52 -04001597bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1598{
1599 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1600}
1601
Geoff Langef7b0162014-09-04 13:29:23 -04001602gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001603{
1604 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1605 ImageD3D *image = mImageArray[faceIndex][level];
1606
1607 if (image->isDirty())
1608 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001609 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1610 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1611 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001612 gl::Error error = commitRegion(index, region);
1613 if (error.isError())
1614 {
1615 return error;
1616 }
Brandon Jones0511e802014-07-14 16:27:26 -07001617 }
Geoff Langef7b0162014-09-04 13:29:23 -04001618
1619 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001620}
1621
1622void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1623{
1624 // If there currently is a corresponding storage texture image, it has these parameters
1625 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1626 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1627 const GLenum storageFormat = getBaseLevelInternalFormat();
1628
1629 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1630
1631 if (mTexStorage)
1632 {
1633 const int storageLevels = mTexStorage->getLevelCount();
1634
1635 if ((level >= storageLevels && storageLevels != 0) ||
1636 width != storageWidth ||
1637 height != storageHeight ||
1638 internalformat != storageFormat) // Discard mismatched storage
1639 {
1640 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1641 {
1642 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1643 {
1644 mImageArray[faceIndex][level]->markDirty();
1645 }
1646 }
1647
1648 SafeDelete(mTexStorage);
1649
1650 mDirtyImages = true;
1651 }
1652 }
1653}
1654
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001655gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1656{
1657 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1658}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001659
Jamie Madillcb83dc12014-09-29 10:46:12 -04001660gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1661{
1662 // The "layer" of the image index corresponds to the cube face
1663 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1664}
1665
Jamie Madill710e5772014-10-20 17:13:53 -04001666bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1667{
1668 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1669 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1670}
1671
Jamie Madill93e13fb2014-11-06 15:27:25 -05001672TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001673 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674{
1675 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1676 {
1677 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1678 }
1679}
1680
1681TextureD3D_3D::~TextureD3D_3D()
1682{
Austin Kinross69822602014-08-12 15:51:37 -07001683 // Delete the Images before the TextureStorage.
1684 // Images might be relying on the TextureStorage for some of their data.
1685 // 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 -07001686 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1687 {
1688 delete mImageArray[i];
1689 }
Austin Kinross69822602014-08-12 15:51:37 -07001690
1691 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001692}
1693
Brandon Jonescef06ff2014-08-05 13:27:48 -07001694Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001695{
1696 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001697 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001698 return mImageArray[level];
1699}
1700
Jamie Madillfeda4d22014-09-17 13:03:29 -04001701Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1702{
1703 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001704 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001705 ASSERT(index.type == GL_TEXTURE_3D);
1706 return mImageArray[index.mipIndex];
1707}
1708
Brandon Jonescef06ff2014-08-05 13:27:48 -07001709GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001710{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001711 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1712 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001713}
1714
Brandon Jones78b1acd2014-07-15 15:33:07 -07001715GLsizei TextureD3D_3D::getWidth(GLint level) const
1716{
1717 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1718 return mImageArray[level]->getWidth();
1719 else
1720 return 0;
1721}
1722
1723GLsizei TextureD3D_3D::getHeight(GLint level) const
1724{
1725 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1726 return mImageArray[level]->getHeight();
1727 else
1728 return 0;
1729}
1730
1731GLsizei TextureD3D_3D::getDepth(GLint level) const
1732{
1733 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1734 return mImageArray[level]->getDepth();
1735 else
1736 return 0;
1737}
1738
1739GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1740{
1741 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1742 return mImageArray[level]->getInternalFormat();
1743 else
1744 return GL_NONE;
1745}
1746
1747bool TextureD3D_3D::isDepth(GLint level) const
1748{
Geoff Lang5d601382014-07-22 15:14:06 -04001749 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001750}
1751
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001752gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1753 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1754 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001755{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001756 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001757 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1758
Brandon Jones78b1acd2014-07-15 15:33:07 -07001759 redefineImage(level, sizedInternalFormat, width, height, depth);
1760
1761 bool fastUnpacked = false;
1762
Jamie Madillba6bc952014-10-06 10:56:22 -04001763 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1764
Brandon Jones78b1acd2014-07-15 15:33:07 -07001765 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1766 if (isFastUnpackable(unpack, sizedInternalFormat))
1767 {
1768 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001769 RenderTarget *destRenderTarget = NULL;
1770 gl::Error error = getRenderTarget(index, &destRenderTarget);
1771 if (error.isError())
1772 {
1773 return error;
1774 }
1775
Brandon Jones78b1acd2014-07-15 15:33:07 -07001776 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1777
Geoff Lang64f23f62014-09-10 14:40:12 -04001778 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1779 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001780 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001781 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001782 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001783
1784 // Ensure we don't overwrite our newly initialized data
1785 mImageArray[level]->markClean();
1786
1787 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001788 }
1789
1790 if (!fastUnpacked)
1791 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001792 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001793 if (error.isError())
1794 {
1795 return error;
1796 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001797 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001798
1799 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001800}
1801
Geoff Langb5348332014-09-02 13:16:34 -04001802gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1803 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001804 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001805{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001806 ASSERT(target == GL_TEXTURE_3D);
1807
Brandon Jones78b1acd2014-07-15 15:33:07 -07001808 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1809 redefineImage(level, format, width, height, depth);
1810
Jamie Madillc751d1e2014-10-21 17:46:29 -04001811 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812}
1813
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001814gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1815 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1816 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001817{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001818 ASSERT(target == GL_TEXTURE_3D);
1819
Brandon Jones78b1acd2014-07-15 15:33:07 -07001820 bool fastUnpacked = false;
1821
Jamie Madillac7579c2014-09-17 16:59:33 -04001822 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1823
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1825 if (isFastUnpackable(unpack, getInternalFormat(level)))
1826 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001827 RenderTarget *destRenderTarget = NULL;
1828 gl::Error error = getRenderTarget(index, &destRenderTarget);
1829 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001831 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001832 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001833
1834 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1835 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1836 if (error.isError())
1837 {
1838 return error;
1839 }
1840
1841 // Ensure we don't overwrite our newly initialized data
1842 mImageArray[level]->markClean();
1843
1844 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001845 }
1846
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001847 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001849 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1850 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001851 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001852
1853 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854}
1855
Geoff Langb5348332014-09-02 13:16:34 -04001856gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1857 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001858 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001859{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001860 ASSERT(target == GL_TEXTURE_3D);
1861
Geoff Langb5348332014-09-02 13:16:34 -04001862 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001863 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001864 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001865 {
Geoff Langb5348332014-09-02 13:16:34 -04001866 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001867 }
Geoff Langb5348332014-09-02 13:16:34 -04001868
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001869 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1870 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1871 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001872}
1873
Geoff Langef7b0162014-09-04 13:29:23 -04001874gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1875 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001876{
1877 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001878 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001879}
1880
Geoff Langef7b0162014-09-04 13:29:23 -04001881gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1882 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001883{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001884 ASSERT(target == GL_TEXTURE_3D);
1885
Jamie Madill82bf0c52014-10-03 11:50:53 -04001886 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001887 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001888
Jamie Madille76bdda2014-10-20 17:13:52 -04001889 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001890 {
Geoff Langef7b0162014-09-04 13:29:23 -04001891 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1892 if (error.isError())
1893 {
1894 return error;
1895 }
1896
Brandon Jones78b1acd2014-07-15 15:33:07 -07001897 mDirtyImages = true;
1898 }
1899 else
1900 {
Geoff Langef7b0162014-09-04 13:29:23 -04001901 gl::Error error = ensureRenderTarget();
1902 if (error.isError())
1903 {
1904 return error;
1905 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001906
1907 if (isValidLevel(level))
1908 {
Geoff Langef7b0162014-09-04 13:29:23 -04001909 error = updateStorageLevel(level);
1910 if (error.isError())
1911 {
1912 return error;
1913 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001914
Geoff Langef7b0162014-09-04 13:29:23 -04001915 error = mRenderer->copyImage3D(source, sourceRect,
1916 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1917 xoffset, yoffset, zoffset, mTexStorage, level);
1918 if (error.isError())
1919 {
1920 return error;
1921 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001922 }
1923 }
Geoff Langef7b0162014-09-04 13:29:23 -04001924
1925 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001926}
1927
Geoff Lang1f8532b2014-09-05 09:46:13 -04001928gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001929{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001930 ASSERT(target == GL_TEXTURE_3D);
1931
Brandon Jones78b1acd2014-07-15 15:33:07 -07001932 for (int level = 0; level < levels; level++)
1933 {
1934 GLsizei levelWidth = std::max(1, width >> level);
1935 GLsizei levelHeight = std::max(1, height >> level);
1936 GLsizei levelDepth = std::max(1, depth >> level);
1937 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1938 }
1939
1940 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1941 {
1942 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1943 }
1944
Geoff Lang1f8532b2014-09-05 09:46:13 -04001945 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001946 bool renderTarget = IsRenderTargetUsage(mUsage);
1947 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001948
1949 gl::Error error = setCompleteTexStorage(storage);
1950 if (error.isError())
1951 {
1952 SafeDelete(storage);
1953 return error;
1954 }
1955
1956 mImmutable = true;
1957
1958 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001959}
1960
Brandon Jones6053a522014-07-25 16:22:09 -07001961void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001962{
Brandon Jones6053a522014-07-25 16:22:09 -07001963 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001964}
1965
Brandon Jones6053a522014-07-25 16:22:09 -07001966void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001967{
Brandon Jones6053a522014-07-25 16:22:09 -07001968 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001969}
1970
Brandon Jones6053a522014-07-25 16:22:09 -07001971
Jamie Madill4aa79e12014-09-29 10:46:14 -04001972void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001973{
1974 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1975 int levelCount = mipLevels();
1976 for (int level = 1; level < levelCount; level++)
1977 {
1978 redefineImage(level, getBaseLevelInternalFormat(),
1979 std::max(getBaseLevelWidth() >> level, 1),
1980 std::max(getBaseLevelHeight() >> level, 1),
1981 std::max(getBaseLevelDepth() >> level, 1));
1982 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001983}
1984
Jamie Madillac7579c2014-09-17 16:59:33 -04001985unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001986{
Geoff Langef7b0162014-09-04 13:29:23 -04001987 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001988}
1989
Geoff Lang64f23f62014-09-10 14:40:12 -04001990gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001991{
1992 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001993 gl::Error error = ensureRenderTarget();
1994 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001995 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001996 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001997 }
1998
Jamie Madillac7579c2014-09-17 16:59:33 -04001999 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002000 {
Geoff Langef7b0162014-09-04 13:29:23 -04002001 error = updateStorage();
2002 if (error.isError())
2003 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002004 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002005 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002006 }
2007 else
2008 {
Geoff Langef7b0162014-09-04 13:29:23 -04002009 error = updateStorageLevel(index.mipIndex);
2010 if (error.isError())
2011 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002012 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002013 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002014 }
2015
Geoff Lang64f23f62014-09-10 14:40:12 -04002016 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002017}
2018
Geoff Langef7b0162014-09-04 13:29:23 -04002019gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020{
2021 // Only initialize the first time this texture is used as a render target or shader resource
2022 if (mTexStorage)
2023 {
Geoff Langef7b0162014-09-04 13:29:23 -04002024 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002025 }
2026
2027 // do not attempt to create storage for nonexistant data
2028 if (!isLevelComplete(0))
2029 {
Geoff Langef7b0162014-09-04 13:29:23 -04002030 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002031 }
2032
2033 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2034
Jamie Madill30d6c252014-11-13 10:03:33 -05002035 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002036 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2037 if (error.isError())
2038 {
2039 return error;
2040 }
2041
2042 error = setCompleteTexStorage(storage);
2043 if (error.isError())
2044 {
2045 SafeDelete(storage);
2046 return error;
2047 }
2048
Brandon Jones78b1acd2014-07-15 15:33:07 -07002049 ASSERT(mTexStorage);
2050
2051 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002052 error = updateStorage();
2053 if (error.isError())
2054 {
2055 return error;
2056 }
2057
2058 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002059}
2060
Geoff Langef7b0162014-09-04 13:29:23 -04002061gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062{
2063 GLsizei width = getBaseLevelWidth();
2064 GLsizei height = getBaseLevelHeight();
2065 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002066 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002067
2068 ASSERT(width > 0 && height > 0 && depth > 0);
2069
2070 // use existing storage level count, when previously specified by TexStorage*D
2071 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2072
Geoff Langef7b0162014-09-04 13:29:23 -04002073 // TODO: Verify creation of the storage succeeded
2074 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2075
2076 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002077}
2078
Geoff Langef7b0162014-09-04 13:29:23 -04002079gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002080{
2081 SafeDelete(mTexStorage);
2082 mTexStorage = newCompleteTexStorage;
2083 mDirtyImages = true;
2084
2085 // We do not support managed 3D storage, as that is D3D9/ES2-only
2086 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002087
2088 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002089}
2090
Geoff Langef7b0162014-09-04 13:29:23 -04002091gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002092{
2093 ASSERT(mTexStorage != NULL);
2094 GLint storageLevels = mTexStorage->getLevelCount();
2095 for (int level = 0; level < storageLevels; level++)
2096 {
2097 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2098 {
Geoff Langef7b0162014-09-04 13:29:23 -04002099 gl::Error error = updateStorageLevel(level);
2100 if (error.isError())
2101 {
2102 return error;
2103 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002104 }
2105 }
Geoff Langef7b0162014-09-04 13:29:23 -04002106
2107 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002108}
2109
Brandon Jones78b1acd2014-07-15 15:33:07 -07002110bool TextureD3D_3D::isValidLevel(int level) const
2111{
2112 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2113}
2114
2115bool TextureD3D_3D::isLevelComplete(int level) const
2116{
2117 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2118
2119 if (isImmutable())
2120 {
2121 return true;
2122 }
2123
2124 GLsizei width = getBaseLevelWidth();
2125 GLsizei height = getBaseLevelHeight();
2126 GLsizei depth = getBaseLevelDepth();
2127
2128 if (width <= 0 || height <= 0 || depth <= 0)
2129 {
2130 return false;
2131 }
2132
2133 if (level == 0)
2134 {
2135 return true;
2136 }
2137
2138 ImageD3D *levelImage = mImageArray[level];
2139
2140 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2141 {
2142 return false;
2143 }
2144
2145 if (levelImage->getWidth() != std::max(1, width >> level))
2146 {
2147 return false;
2148 }
2149
2150 if (levelImage->getHeight() != std::max(1, height >> level))
2151 {
2152 return false;
2153 }
2154
2155 if (levelImage->getDepth() != std::max(1, depth >> level))
2156 {
2157 return false;
2158 }
2159
2160 return true;
2161}
2162
Jamie Madille76bdda2014-10-20 17:13:52 -04002163bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2164{
2165 return isLevelComplete(index.mipIndex);
2166}
2167
Geoff Langef7b0162014-09-04 13:29:23 -04002168gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002169{
2170 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2171 ASSERT(isLevelComplete(level));
2172
2173 if (mImageArray[level]->isDirty())
2174 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002175 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2176 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002177 gl::Error error = commitRegion(index, region);
2178 if (error.isError())
2179 {
2180 return error;
2181 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002182 }
Geoff Langef7b0162014-09-04 13:29:23 -04002183
2184 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002185}
2186
2187void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2188{
2189 // If there currently is a corresponding storage texture image, it has these parameters
2190 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2191 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2192 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2193 const GLenum storageFormat = getBaseLevelInternalFormat();
2194
2195 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2196
2197 if (mTexStorage)
2198 {
2199 const int storageLevels = mTexStorage->getLevelCount();
2200
2201 if ((level >= storageLevels && storageLevels != 0) ||
2202 width != storageWidth ||
2203 height != storageHeight ||
2204 depth != storageDepth ||
2205 internalformat != storageFormat) // Discard mismatched storage
2206 {
2207 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2208 {
2209 mImageArray[i]->markDirty();
2210 }
2211
2212 SafeDelete(mTexStorage);
2213 mDirtyImages = true;
2214 }
2215 }
2216}
2217
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002218gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2219{
2220 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2221 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2222}
Brandon Jones142ec422014-07-16 10:31:30 -07002223
Jamie Madillcb83dc12014-09-29 10:46:12 -04002224gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2225{
2226 // The "layer" here does not apply to 3D images. We use one Image per mip.
2227 return gl::ImageIndex::Make3D(mip);
2228}
2229
Jamie Madill710e5772014-10-20 17:13:53 -04002230bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2231{
2232 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2233 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2234}
2235
Jamie Madill93e13fb2014-11-06 15:27:25 -05002236TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002237 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002238{
2239 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2240 {
2241 mLayerCounts[level] = 0;
2242 mImageArray[level] = NULL;
2243 }
2244}
2245
2246TextureD3D_2DArray::~TextureD3D_2DArray()
2247{
Austin Kinross69822602014-08-12 15:51:37 -07002248 // Delete the Images before the TextureStorage.
2249 // Images might be relying on the TextureStorage for some of their data.
2250 // 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 -07002251 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002252 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002253}
2254
Brandon Jones142ec422014-07-16 10:31:30 -07002255Image *TextureD3D_2DArray::getImage(int level, int layer) const
2256{
2257 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002258 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2259 layer < mLayerCounts[level]);
2260 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002261}
2262
Jamie Madillfeda4d22014-09-17 13:03:29 -04002263Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2264{
2265 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002266 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2267 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002268 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002269 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002270}
2271
Brandon Jones142ec422014-07-16 10:31:30 -07002272GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2273{
2274 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2275 return mLayerCounts[level];
2276}
2277
Brandon Jones142ec422014-07-16 10:31:30 -07002278GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2279{
2280 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2281}
2282
2283GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2284{
2285 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2286}
2287
Brandon Jones142ec422014-07-16 10:31:30 -07002288GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2289{
2290 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2291}
2292
2293bool TextureD3D_2DArray::isDepth(GLint level) const
2294{
Geoff Lang5d601382014-07-22 15:14:06 -04002295 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002296}
2297
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002298gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2299 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2300 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002301{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002302 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2303
Geoff Lang5d601382014-07-22 15:14:06 -04002304 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2305
Brandon Jones142ec422014-07-16 10:31:30 -07002306 redefineImage(level, sizedInternalFormat, width, height, depth);
2307
Geoff Lang5d601382014-07-22 15:14:06 -04002308 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2309 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002310
2311 for (int i = 0; i < depth; i++)
2312 {
2313 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002314 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2315 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002316 if (error.isError())
2317 {
2318 return error;
2319 }
Brandon Jones142ec422014-07-16 10:31:30 -07002320 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002321
2322 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002323}
2324
Geoff Langb5348332014-09-02 13:16:34 -04002325gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2326 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002327 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002328{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002329 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2330
Brandon Jones142ec422014-07-16 10:31:30 -07002331 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2332 redefineImage(level, format, width, height, depth);
2333
Geoff Lang5d601382014-07-22 15:14:06 -04002334 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2335 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002336
2337 for (int i = 0; i < depth; i++)
2338 {
2339 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002340 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002341 if (error.isError())
2342 {
2343 return error;
2344 }
Brandon Jones142ec422014-07-16 10:31:30 -07002345 }
Geoff Langb5348332014-09-02 13:16:34 -04002346
2347 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002348}
2349
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002350gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2351 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2352 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002353{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002354 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2355
Geoff Lang5d601382014-07-22 15:14:06 -04002356 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2357 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002358
2359 for (int i = 0; i < depth; i++)
2360 {
2361 int layer = zoffset + i;
2362 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2363
Jamie Madillfeda4d22014-09-17 13:03:29 -04002364 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002365 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2366 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002367 if (error.isError())
2368 {
2369 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002370 }
2371 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002372
2373 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002374}
2375
Geoff Langb5348332014-09-02 13:16:34 -04002376gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2377 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002378 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002379{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002380 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2381
Geoff Lang5d601382014-07-22 15:14:06 -04002382 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2383 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002384
2385 for (int i = 0; i < depth; i++)
2386 {
2387 int layer = zoffset + i;
2388 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2389
Jamie Madillc751d1e2014-10-21 17:46:29 -04002390 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 -04002391 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002392 {
Geoff Langb5348332014-09-02 13:16:34 -04002393 return error;
2394 }
2395
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002396 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2397 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2398 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002399 if (error.isError())
2400 {
2401 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002402 }
2403 }
Geoff Langb5348332014-09-02 13:16:34 -04002404
2405 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002406}
2407
Geoff Langef7b0162014-09-04 13:29:23 -04002408gl::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 -07002409{
2410 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002411 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002412}
2413
Geoff Langef7b0162014-09-04 13:29:23 -04002414gl::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 -07002415{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002416 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2417
Jamie Madill82bf0c52014-10-03 11:50:53 -04002418 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002419 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002420
Jamie Madille76bdda2014-10-20 17:13:52 -04002421 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002422 {
Geoff Langef7b0162014-09-04 13:29:23 -04002423 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2424 if (error.isError())
2425 {
2426 return error;
2427 }
2428
Brandon Jones142ec422014-07-16 10:31:30 -07002429 mDirtyImages = true;
2430 }
2431 else
2432 {
Geoff Langef7b0162014-09-04 13:29:23 -04002433 gl::Error error = ensureRenderTarget();
2434 if (error.isError())
2435 {
2436 return error;
2437 }
Brandon Jones142ec422014-07-16 10:31:30 -07002438
2439 if (isValidLevel(level))
2440 {
Geoff Langef7b0162014-09-04 13:29:23 -04002441 error = updateStorageLevel(level);
2442 if (error.isError())
2443 {
2444 return error;
2445 }
Brandon Jones142ec422014-07-16 10:31:30 -07002446
Geoff Langef7b0162014-09-04 13:29:23 -04002447 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2448 xoffset, yoffset, zoffset, mTexStorage, level);
2449 if (error.isError())
2450 {
2451 return error;
2452 }
Brandon Jones142ec422014-07-16 10:31:30 -07002453 }
2454 }
Geoff Langef7b0162014-09-04 13:29:23 -04002455 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002456}
2457
Geoff Lang1f8532b2014-09-05 09:46:13 -04002458gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002459{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002460 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2461
Brandon Jones142ec422014-07-16 10:31:30 -07002462 deleteImages();
2463
2464 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2465 {
2466 GLsizei levelWidth = std::max(1, width >> level);
2467 GLsizei levelHeight = std::max(1, height >> level);
2468
2469 mLayerCounts[level] = (level < levels ? depth : 0);
2470
2471 if (mLayerCounts[level] > 0)
2472 {
2473 // Create new images for this level
2474 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2475
2476 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2477 {
2478 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2479 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2480 levelHeight, 1, true);
2481 }
2482 }
2483 }
2484
Geoff Lang1f8532b2014-09-05 09:46:13 -04002485 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002486 bool renderTarget = IsRenderTargetUsage(mUsage);
2487 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002488
2489 gl::Error error = setCompleteTexStorage(storage);
2490 if (error.isError())
2491 {
2492 SafeDelete(storage);
2493 return error;
2494 }
2495
2496 mImmutable = true;
2497
2498 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002499}
2500
Brandon Jones6053a522014-07-25 16:22:09 -07002501void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002502{
Brandon Jones6053a522014-07-25 16:22:09 -07002503 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002504}
2505
Brandon Jones6053a522014-07-25 16:22:09 -07002506void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002507{
Brandon Jones6053a522014-07-25 16:22:09 -07002508 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002509}
2510
Brandon Jones6053a522014-07-25 16:22:09 -07002511
Jamie Madill4aa79e12014-09-29 10:46:14 -04002512void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002513{
2514 int baseWidth = getBaseLevelWidth();
2515 int baseHeight = getBaseLevelHeight();
2516 int baseDepth = getBaseLevelDepth();
2517 GLenum baseFormat = getBaseLevelInternalFormat();
2518
2519 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2520 int levelCount = mipLevels();
2521 for (int level = 1; level < levelCount; level++)
2522 {
2523 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2524 }
Brandon Jones142ec422014-07-16 10:31:30 -07002525}
2526
Jamie Madillac7579c2014-09-17 16:59:33 -04002527unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002528{
Geoff Langef7b0162014-09-04 13:29:23 -04002529 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002530}
2531
Geoff Lang64f23f62014-09-10 14:40:12 -04002532gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002533{
2534 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002535 gl::Error error = ensureRenderTarget();
2536 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002537 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002538 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002539 }
2540
Geoff Langef7b0162014-09-04 13:29:23 -04002541 error = updateStorageLevel(index.mipIndex);
2542 if (error.isError())
2543 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002544 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002545 }
2546
Geoff Lang64f23f62014-09-10 14:40:12 -04002547 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002548}
2549
Geoff Langef7b0162014-09-04 13:29:23 -04002550gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002551{
2552 // Only initialize the first time this texture is used as a render target or shader resource
2553 if (mTexStorage)
2554 {
Geoff Langef7b0162014-09-04 13:29:23 -04002555 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002556 }
2557
2558 // do not attempt to create storage for nonexistant data
2559 if (!isLevelComplete(0))
2560 {
Geoff Langef7b0162014-09-04 13:29:23 -04002561 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002562 }
2563
2564 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2565
Geoff Langef7b0162014-09-04 13:29:23 -04002566 TextureStorage *storage = NULL;
2567 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2568 if (error.isError())
2569 {
2570 return error;
2571 }
2572
2573 error = setCompleteTexStorage(storage);
2574 if (error.isError())
2575 {
2576 SafeDelete(storage);
2577 return error;
2578 }
2579
Brandon Jones142ec422014-07-16 10:31:30 -07002580 ASSERT(mTexStorage);
2581
2582 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002583 error = updateStorage();
2584 if (error.isError())
2585 {
2586 return error;
2587 }
2588
2589 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002590}
2591
Geoff Langef7b0162014-09-04 13:29:23 -04002592gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002593{
2594 GLsizei width = getBaseLevelWidth();
2595 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002596 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002597 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002598
2599 ASSERT(width > 0 && height > 0 && depth > 0);
2600
2601 // use existing storage level count, when previously specified by TexStorage*D
2602 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2603
Geoff Langef7b0162014-09-04 13:29:23 -04002604 // TODO(geofflang): Verify storage creation succeeds
2605 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2606
2607 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002608}
2609
Geoff Langef7b0162014-09-04 13:29:23 -04002610gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002611{
2612 SafeDelete(mTexStorage);
2613 mTexStorage = newCompleteTexStorage;
2614 mDirtyImages = true;
2615
2616 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2617 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002618
2619 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002620}
2621
Geoff Langef7b0162014-09-04 13:29:23 -04002622gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002623{
2624 ASSERT(mTexStorage != NULL);
2625 GLint storageLevels = mTexStorage->getLevelCount();
2626 for (int level = 0; level < storageLevels; level++)
2627 {
2628 if (isLevelComplete(level))
2629 {
Geoff Langef7b0162014-09-04 13:29:23 -04002630 gl::Error error = updateStorageLevel(level);
2631 if (error.isError())
2632 {
2633 return error;
2634 }
Brandon Jones142ec422014-07-16 10:31:30 -07002635 }
2636 }
Geoff Langef7b0162014-09-04 13:29:23 -04002637
2638 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002639}
2640
Brandon Jones142ec422014-07-16 10:31:30 -07002641bool TextureD3D_2DArray::isValidLevel(int level) const
2642{
2643 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2644}
2645
2646bool TextureD3D_2DArray::isLevelComplete(int level) const
2647{
2648 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2649
2650 if (isImmutable())
2651 {
2652 return true;
2653 }
2654
2655 GLsizei width = getBaseLevelWidth();
2656 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002657 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002658
2659 if (width <= 0 || height <= 0 || layers <= 0)
2660 {
2661 return false;
2662 }
2663
2664 if (level == 0)
2665 {
2666 return true;
2667 }
2668
2669 if (getInternalFormat(level) != getInternalFormat(0))
2670 {
2671 return false;
2672 }
2673
2674 if (getWidth(level) != std::max(1, width >> level))
2675 {
2676 return false;
2677 }
2678
2679 if (getHeight(level) != std::max(1, height >> level))
2680 {
2681 return false;
2682 }
2683
Jamie Madill3269bcb2014-09-30 16:33:52 -04002684 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002685 {
2686 return false;
2687 }
2688
2689 return true;
2690}
2691
Jamie Madille76bdda2014-10-20 17:13:52 -04002692bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2693{
2694 return isLevelComplete(index.mipIndex);
2695}
2696
Geoff Langef7b0162014-09-04 13:29:23 -04002697gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002698{
2699 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2700 ASSERT(isLevelComplete(level));
2701
2702 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2703 {
2704 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2705 if (mImageArray[level][layer]->isDirty())
2706 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002707 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2708 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002709 gl::Error error = commitRegion(index, region);
2710 if (error.isError())
2711 {
2712 return error;
2713 }
Brandon Jones142ec422014-07-16 10:31:30 -07002714 }
2715 }
Geoff Langef7b0162014-09-04 13:29:23 -04002716
2717 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002718}
2719
2720void TextureD3D_2DArray::deleteImages()
2721{
2722 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2723 {
2724 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2725 {
2726 delete mImageArray[level][layer];
2727 }
2728 delete[] mImageArray[level];
2729 mImageArray[level] = NULL;
2730 mLayerCounts[level] = 0;
2731 }
2732}
2733
2734void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2735{
2736 // If there currently is a corresponding storage texture image, it has these parameters
2737 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2738 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002739 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002740 const GLenum storageFormat = getBaseLevelInternalFormat();
2741
2742 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2743 {
2744 delete mImageArray[level][layer];
2745 }
2746 delete[] mImageArray[level];
2747 mImageArray[level] = NULL;
2748 mLayerCounts[level] = depth;
2749
2750 if (depth > 0)
2751 {
2752 mImageArray[level] = new ImageD3D*[depth]();
2753
2754 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2755 {
2756 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2757 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2758 }
2759 }
2760
2761 if (mTexStorage)
2762 {
2763 const int storageLevels = mTexStorage->getLevelCount();
2764
2765 if ((level >= storageLevels && storageLevels != 0) ||
2766 width != storageWidth ||
2767 height != storageHeight ||
2768 depth != storageDepth ||
2769 internalformat != storageFormat) // Discard mismatched storage
2770 {
2771 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2772 {
2773 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2774 {
2775 mImageArray[level][layer]->markDirty();
2776 }
2777 }
2778
2779 delete mTexStorage;
2780 mTexStorage = NULL;
2781 mDirtyImages = true;
2782 }
2783 }
2784}
2785
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002786gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2787{
2788 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2789}
2790
Jamie Madillcb83dc12014-09-29 10:46:12 -04002791gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2792{
2793 return gl::ImageIndex::Make2DArray(mip, layer);
2794}
2795
Jamie Madill710e5772014-10-20 17:13:53 -04002796bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2797{
2798 // Check for having a storage and the right type of index
2799 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2800 {
2801 return false;
2802 }
2803
2804 // Check the mip index
2805 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2806 {
2807 return false;
2808 }
2809
2810 // Check the layer index
2811 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2812}
2813
Brandon Jones78b1acd2014-07-15 15:33:07 -07002814}