blob: ea27c087802c95bf93b1c5cb9fc4b296e0c2fb64 [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
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.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
Brandon Jonesf47bebc2014-07-09 14:28:42 -070029bool IsRenderTargetUsage(GLenum usage)
30{
31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
32}
33
Brandon Jones78b1acd2014-07-15 15:33:07 -070034TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070035 : mRenderer(renderer),
36 mUsage(GL_NONE),
37 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040038 mImmutable(false),
39 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070040{
41}
42
43TextureD3D::~TextureD3D()
44{
45}
46
Brandon Jones6053a522014-07-25 16:22:09 -070047TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
48{
49 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
50 return static_cast<TextureD3D*>(texture);
51}
52
Jamie Madill2f06dbf2014-09-18 15:08:50 -040053TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070054{
55 // ensure the underlying texture is created
56 initializeStorage(false);
57
Jamie Madill98553e32014-09-30 16:33:50 -040058 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070059 {
60 updateStorage();
61 }
62
Jamie Madill98553e32014-09-30 16:33:50 -040063 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070064}
65
Brandon Jonesf47bebc2014-07-09 14:28:42 -070066GLint TextureD3D::getBaseLevelWidth() const
67{
Brandon Jones78b1acd2014-07-15 15:33:07 -070068 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 return (baseImage ? baseImage->getWidth() : 0);
70}
71
72GLint TextureD3D::getBaseLevelHeight() const
73{
Brandon Jones78b1acd2014-07-15 15:33:07 -070074 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075 return (baseImage ? baseImage->getHeight() : 0);
76}
77
78GLint TextureD3D::getBaseLevelDepth() const
79{
Brandon Jones78b1acd2014-07-15 15:33:07 -070080 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070081 return (baseImage ? baseImage->getDepth() : 0);
82}
83
84// Note: "base level image" is loosely defined to be any image from the base level,
85// where in the base of 2D array textures and cube maps there are several. Don't use
86// the base level image for anything except querying texture format and size.
87GLenum TextureD3D::getBaseLevelInternalFormat() const
88{
Brandon Jones78b1acd2014-07-15 15:33:07 -070089 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070090 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
91}
92
Jamie Madillec6de4e2014-10-20 10:59:56 -040093bool TextureD3D::shouldUseSetData(const Image *image) const
94{
95 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
96 {
97 return false;
98 }
99
100 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
101
102 // We can only handle full updates for depth-stencil textures, so to avoid complications
103 // disable them entirely.
104 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
105 {
106 return false;
107 }
108
109 // TODO(jmadill): Handle compressed internal formats
110 return (mTexStorage && !internalFormat.compressed);
111}
112
Jamie Madillba6bc952014-10-06 10:56:22 -0400113gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700114{
Jamie Madillba6bc952014-10-06 10:56:22 -0400115 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400116 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400117
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700118 // No-op
119 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
120 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400121 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700122 }
123
124 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
125 // 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 -0400126 const uint8_t *pixelData = NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700127
128 if (unpack.pixelBuffer.id() != 0)
129 {
130 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
132 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
134 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
135 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400136 pixelData = static_cast<const uint8_t *>(bufferData) + offset;
137 }
138 else
139 {
140 pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700141 }
142
143 if (pixelData != NULL)
144 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400145 gl::Error error(GL_NO_ERROR);
146
Jamie Madillec6de4e2014-10-20 10:59:56 -0400147 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400148 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400149 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400150 }
151 else
152 {
153 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
154 }
155
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400156 if (error.isError())
157 {
158 return error;
159 }
160
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700161 mDirtyImages = true;
162 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400163
164 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165}
166
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400167gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
168 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700169{
Jamie Madill9aca0592014-10-06 16:26:59 -0400170 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700171
172 // CPU readback & copy where direct GPU copy is not supported
173 if (unpack.pixelBuffer.id() != 0)
174 {
175 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200176 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700177 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
178 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
179 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400180 pixelData = static_cast<const uint8_t *>(bufferData)+offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181 }
182
183 if (pixelData != NULL)
184 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400185 Image *image = getImage(index);
186 ASSERT(image);
187
Jamie Madill9aca0592014-10-06 16:26:59 -0400188 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400189 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400190 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400191 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400192 }
193
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400194 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
195 type, pixelData);
196 if (error.isError())
197 {
198 return error;
199 }
200
Jamie Madille6b6da02014-10-02 11:03:14 -0400201 error = commitRegion(index, region);
202 if (error.isError())
203 {
204 return error;
205 }
206
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700207 mDirtyImages = true;
208 }
209
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400210 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211}
212
Geoff Langb5348332014-09-02 13:16:34 -0400213gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700214{
215 if (pixels != NULL)
216 {
Geoff Langb5348332014-09-02 13:16:34 -0400217 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
218 if (error.isError())
219 {
220 return error;
221 }
222
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700223 mDirtyImages = true;
224 }
Geoff Langb5348332014-09-02 13:16:34 -0400225
226 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227}
228
Geoff Langb5348332014-09-02 13:16:34 -0400229gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700230 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231{
232 if (pixels != NULL)
233 {
Geoff Langb5348332014-09-02 13:16:34 -0400234 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
235 if (error.isError())
236 {
237 return error;
238 }
239
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240 mDirtyImages = true;
241 }
242
Geoff Langb5348332014-09-02 13:16:34 -0400243 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700244}
245
246bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
247{
248 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
249}
250
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400251gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
252 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700253{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400254 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700255 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
256 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400257 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258 }
259
260 // In order to perform the fast copy through the shader, we must have the right format, and be able
261 // to create a render target.
262 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
263
Jacek Cabana5521de2014-10-01 17:23:46 +0200264 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700265
Geoff Langae5122c2014-08-27 14:08:43 -0400266 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
267 if (error.isError())
268 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400269 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400270 }
271
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400272 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700273}
274
275GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
276{
277 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
278 {
279 // Maximum number of levels
280 return gl::log2(std::max(std::max(width, height), depth)) + 1;
281 }
282 else
283 {
284 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
285 return 1;
286 }
287}
288
289int TextureD3D::mipLevels() const
290{
291 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
292}
293
Jamie Madill98553e32014-09-30 16:33:50 -0400294TextureStorage *TextureD3D::getStorage()
295{
296 return mTexStorage;
297}
298
Jamie Madill3269bcb2014-09-30 16:33:52 -0400299Image *TextureD3D::getBaseLevelImage() const
300{
301 return getImage(getImageIndex(0, 0));
302}
303
Jamie Madill4aa79e12014-09-29 10:46:14 -0400304void TextureD3D::generateMipmaps()
305{
Jamie Madill9aca0592014-10-06 16:26:59 -0400306 GLint mipCount = mipLevels();
307
308 if (mipCount == 1)
309 {
310 return; // no-op
311 }
312
313 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400314 initMipmapsImages();
315
316 // We know that all layers have the same dimension, for the texture to be complete
317 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400318
Jamie Madill9aca0592014-10-06 16:26:59 -0400319 // When making mipmaps with the setData workaround enabled, the texture storage has
320 // the image data already. For non-render-target storage, we have to pull it out into
321 // an image layer.
322 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
323 {
324 if (!mTexStorage->isRenderTarget())
325 {
326 // Copy from the storage mip 0 to Image mip 0
327 for (GLint layer = 0; layer < layerCount; ++layer)
328 {
329 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400330
Jamie Madill9aca0592014-10-06 16:26:59 -0400331 Image *image = getImage(srcIndex);
332 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
333 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
334 }
335 }
336 else
337 {
338 updateStorage();
339 }
340 }
341
342 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400343
344 for (GLint layer = 0; layer < layerCount; ++layer)
345 {
346 for (GLint mip = 1; mip < mipCount; ++mip)
347 {
348 ASSERT(getLayerCount(mip) == layerCount);
349
350 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
351 gl::ImageIndex destIndex = getImageIndex(mip, layer);
352
353 if (renderableStorage)
354 {
355 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400356 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400357 }
358 else
359 {
360 // CPU-side mipmapping
361 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
362 }
363 }
364 }
365}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700366
Jamie Madill135570a2014-09-30 16:33:51 -0400367bool TextureD3D::isBaseImageZeroSize() const
368{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400369 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400370
371 if (!baseImage || baseImage->getWidth() <= 0)
372 {
373 return true;
374 }
375
376 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
377 {
378 return true;
379 }
380
381 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
382 {
383 return true;
384 }
385
386 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
387 {
388 return true;
389 }
390
391 return false;
392}
393
Geoff Langef7b0162014-09-04 13:29:23 -0400394gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400395{
Geoff Langef7b0162014-09-04 13:29:23 -0400396 gl::Error error = initializeStorage(true);
397 if (error.isError())
398 {
399 return error;
400 }
Jamie Madill135570a2014-09-30 16:33:51 -0400401
402 if (!isBaseImageZeroSize())
403 {
404 ASSERT(mTexStorage);
405 if (!mTexStorage->isRenderTarget())
406 {
Geoff Langef7b0162014-09-04 13:29:23 -0400407 TextureStorage *newRenderTargetStorage = NULL;
408 error = createCompleteStorage(true, &newRenderTargetStorage);
409 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400410 {
Geoff Langef7b0162014-09-04 13:29:23 -0400411 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400412 }
413
Geoff Langef7b0162014-09-04 13:29:23 -0400414 error = mTexStorage->copyToStorage(newRenderTargetStorage);
415 if (error.isError())
416 {
417 SafeDelete(newRenderTargetStorage);
418 return error;
419 }
420
421 error = setCompleteTexStorage(newRenderTargetStorage);
422 if (error.isError())
423 {
424 SafeDelete(newRenderTargetStorage);
425 return error;
426 }
Jamie Madill135570a2014-09-30 16:33:51 -0400427 }
428 }
429
Geoff Langef7b0162014-09-04 13:29:23 -0400430 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400431}
432
Brandon Jones78b1acd2014-07-15 15:33:07 -0700433TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400434 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435{
436 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
437 {
438 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
439 }
440}
441
442TextureD3D_2D::~TextureD3D_2D()
443{
Austin Kinross69822602014-08-12 15:51:37 -0700444 // Delete the Images before the TextureStorage.
445 // Images might be relying on the TextureStorage for some of their data.
446 // 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 -0700447 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
448 {
449 delete mImageArray[i];
450 }
Austin Kinross69822602014-08-12 15:51:37 -0700451
452 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700453}
454
Brandon Jonescef06ff2014-08-05 13:27:48 -0700455Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700456{
457 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700458 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700459 return mImageArray[level];
460}
461
Jamie Madillfeda4d22014-09-17 13:03:29 -0400462Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
463{
464 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400465 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400466 ASSERT(index.type == GL_TEXTURE_2D);
467 return mImageArray[index.mipIndex];
468}
469
Brandon Jonescef06ff2014-08-05 13:27:48 -0700470GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700471{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700472 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
473 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700474}
475
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700476GLsizei TextureD3D_2D::getWidth(GLint level) const
477{
478 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
479 return mImageArray[level]->getWidth();
480 else
481 return 0;
482}
483
484GLsizei TextureD3D_2D::getHeight(GLint level) const
485{
486 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
487 return mImageArray[level]->getHeight();
488 else
489 return 0;
490}
491
492GLenum TextureD3D_2D::getInternalFormat(GLint level) const
493{
494 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
495 return mImageArray[level]->getInternalFormat();
496 else
497 return GL_NONE;
498}
499
500GLenum TextureD3D_2D::getActualFormat(GLint level) const
501{
502 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
503 return mImageArray[level]->getActualFormat();
504 else
505 return GL_NONE;
506}
507
508bool TextureD3D_2D::isDepth(GLint level) const
509{
Geoff Lang5d601382014-07-22 15:14:06 -0400510 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700511}
512
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400513gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
514 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
515 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700516{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700517 ASSERT(target == GL_TEXTURE_2D && depth == 1);
518
Geoff Lang5d601382014-07-22 15:14:06 -0400519 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
520
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700521 bool fastUnpacked = false;
522
Brandon Jonescef06ff2014-08-05 13:27:48 -0700523 redefineImage(level, sizedInternalFormat, width, height);
524
Jamie Madillba6bc952014-10-06 10:56:22 -0400525 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
526
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700527 // Attempt a fast gpu copy of the pixel data to the surface
528 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
529 {
530 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400531 RenderTarget *destRenderTarget = NULL;
532 gl::Error error = getRenderTarget(index, &destRenderTarget);
533 if (error.isError())
534 {
535 return error;
536 }
537
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
539
Geoff Lang64f23f62014-09-10 14:40:12 -0400540 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
541 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700542 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400543 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700544 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400545
546 // Ensure we don't overwrite our newly initialized data
547 mImageArray[level]->markClean();
548
549 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700550 }
551
552 if (!fastUnpacked)
553 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400554 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400555 if (error.isError())
556 {
557 return error;
558 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700559 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400560
561 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700562}
563
Geoff Langb5348332014-09-02 13:16:34 -0400564gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
565 GLsizei width, GLsizei height, GLsizei depth,
566 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700568 ASSERT(target == GL_TEXTURE_2D && depth == 1);
569
570 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
571 redefineImage(level, format, width, height);
572
Geoff Langb5348332014-09-02 13:16:34 -0400573 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700574}
575
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400576gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
577 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
578 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700580 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
581
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582 bool fastUnpacked = false;
583
Jamie Madillac7579c2014-09-17 16:59:33 -0400584 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400585 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
587 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400588 RenderTarget *renderTarget = NULL;
589 gl::Error error = getRenderTarget(index, &renderTarget);
590 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700591 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400592 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700593 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400594
595 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
596 if (error.isError())
597 {
598 return error;
599 }
600
601 // Ensure we don't overwrite our newly initialized data
602 mImageArray[level]->markClean();
603
604 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700605 }
606
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400607 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400609 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
610 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700611 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400612
613 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614}
615
Geoff Langb5348332014-09-02 13:16:34 -0400616gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
617 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
618 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700620 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
621
Geoff Langb5348332014-09-02 13:16:34 -0400622 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
623 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700624 {
Geoff Langb5348332014-09-02 13:16:34 -0400625 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626 }
Geoff Langb5348332014-09-02 13:16:34 -0400627
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400628 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
629 gl::Box region(xoffset, yoffset, 0, width, height, 1);
630 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631}
632
Geoff Langef7b0162014-09-04 13:29:23 -0400633gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
634 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700636 ASSERT(target == GL_TEXTURE_2D);
637
638 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
639 redefineImage(level, sizedInternalFormat, width, height);
640
Jamie Madill82bf0c52014-10-03 11:50:53 -0400641 gl::Rectangle sourceRect(x, y, width, height);
642
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643 if (!mImageArray[level]->isRenderableFormat())
644 {
Geoff Langef7b0162014-09-04 13:29:23 -0400645 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
646 if (error.isError())
647 {
648 return error;
649 }
650
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651 mDirtyImages = true;
652 }
653 else
654 {
Geoff Langef7b0162014-09-04 13:29:23 -0400655 gl::Error error = ensureRenderTarget();
656 if (error.isError())
657 {
658 return error;
659 }
660
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700661 mImageArray[level]->markClean();
662
663 if (width != 0 && height != 0 && isValidLevel(level))
664 {
Geoff Langef7b0162014-09-04 13:29:23 -0400665 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
666 if (error.isError())
667 {
668 return error;
669 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700670 }
671 }
Geoff Langef7b0162014-09-04 13:29:23 -0400672
673 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674}
675
Geoff Langef7b0162014-09-04 13:29:23 -0400676gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
677 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700678{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700679 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
680
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700681 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
682 // the current level we're copying to is defined (with appropriate format, width & height)
683 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
684
Jamie Madill82bf0c52014-10-03 11:50:53 -0400685 gl::Rectangle sourceRect(x, y, width, height);
686
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700687 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
688 {
Geoff Langef7b0162014-09-04 13:29:23 -0400689 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
690 if (error.isError())
691 {
692 return error;
693 }
694
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700695 mDirtyImages = true;
696 }
697 else
698 {
Geoff Langef7b0162014-09-04 13:29:23 -0400699 gl::Error error = ensureRenderTarget();
700 if (error.isError())
701 {
702 return error;
703 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704
705 if (isValidLevel(level))
706 {
Geoff Langef7b0162014-09-04 13:29:23 -0400707 error = updateStorageLevel(level);
708 if (error.isError())
709 {
710 return error;
711 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712
Geoff Langef7b0162014-09-04 13:29:23 -0400713 error = mRenderer->copyImage2D(source, sourceRect,
714 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
715 xoffset, yoffset, mTexStorage, level);
716 if (error.isError())
717 {
718 return error;
719 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700720 }
721 }
Geoff Langef7b0162014-09-04 13:29:23 -0400722
723 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700724}
725
Geoff Lang1f8532b2014-09-05 09:46:13 -0400726gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700727{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700728 ASSERT(target == GL_TEXTURE_2D && depth == 1);
729
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700730 for (int level = 0; level < levels; level++)
731 {
732 GLsizei levelWidth = std::max(1, width >> level);
733 GLsizei levelHeight = std::max(1, height >> level);
734 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
735 }
736
737 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
738 {
739 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
740 }
741
Geoff Lang1f8532b2014-09-05 09:46:13 -0400742 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400743 bool renderTarget = IsRenderTargetUsage(mUsage);
744 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400745
746 gl::Error error = setCompleteTexStorage(storage);
747 if (error.isError())
748 {
749 SafeDelete(storage);
750 return error;
751 }
752
753 mImmutable = true;
754
755 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700756}
757
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700758void TextureD3D_2D::bindTexImage(egl::Surface *surface)
759{
760 GLenum internalformat = surface->getFormat();
761
762 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
763
764 if (mTexStorage)
765 {
766 SafeDelete(mTexStorage);
767 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400768
769 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770
771 mDirtyImages = true;
772}
773
774void TextureD3D_2D::releaseTexImage()
775{
776 if (mTexStorage)
777 {
778 SafeDelete(mTexStorage);
779 }
780
781 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
782 {
783 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
784 }
785}
786
Jamie Madill4aa79e12014-09-29 10:46:14 -0400787void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700788{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700790 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700791 for (int level = 1; level < levelCount; level++)
792 {
793 redefineImage(level, getBaseLevelInternalFormat(),
794 std::max(getBaseLevelWidth() >> level, 1),
795 std::max(getBaseLevelHeight() >> level, 1));
796 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700797}
798
Jamie Madillac7579c2014-09-17 16:59:33 -0400799unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700800{
Jamie Madillac7579c2014-09-17 16:59:33 -0400801 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400802 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700803}
804
Geoff Lang64f23f62014-09-10 14:40:12 -0400805gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700806{
Jamie Madillac7579c2014-09-17 16:59:33 -0400807 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700808
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400810 gl::Error error = ensureRenderTarget();
811 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400813 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700814 }
815
Geoff Langef7b0162014-09-04 13:29:23 -0400816 error = updateStorageLevel(index.mipIndex);
817 if (error.isError())
818 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400819 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400820 }
821
Geoff Lang64f23f62014-09-10 14:40:12 -0400822 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700823}
824
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700825bool TextureD3D_2D::isValidLevel(int level) const
826{
827 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
828}
829
830bool TextureD3D_2D::isLevelComplete(int level) const
831{
832 if (isImmutable())
833 {
834 return true;
835 }
836
Brandon Jones78b1acd2014-07-15 15:33:07 -0700837 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700838
839 GLsizei width = baseImage->getWidth();
840 GLsizei height = baseImage->getHeight();
841
842 if (width <= 0 || height <= 0)
843 {
844 return false;
845 }
846
847 // The base image level is complete if the width and height are positive
848 if (level == 0)
849 {
850 return true;
851 }
852
853 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700854 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700855
856 if (image->getInternalFormat() != baseImage->getInternalFormat())
857 {
858 return false;
859 }
860
861 if (image->getWidth() != std::max(1, width >> level))
862 {
863 return false;
864 }
865
866 if (image->getHeight() != std::max(1, height >> level))
867 {
868 return false;
869 }
870
871 return true;
872}
873
874// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400875gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700876{
877 // Only initialize the first time this texture is used as a render target or shader resource
878 if (mTexStorage)
879 {
Geoff Langef7b0162014-09-04 13:29:23 -0400880 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700881 }
882
883 // do not attempt to create storage for nonexistant data
884 if (!isLevelComplete(0))
885 {
Geoff Langef7b0162014-09-04 13:29:23 -0400886 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700887 }
888
889 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
890
Geoff Langef7b0162014-09-04 13:29:23 -0400891 TextureStorage *storage = NULL;
892 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
893 if (error.isError())
894 {
895 return error;
896 }
897
898 error = setCompleteTexStorage(storage);
899 if (error.isError())
900 {
901 SafeDelete(storage);
902 return error;
903 }
904
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700905 ASSERT(mTexStorage);
906
907 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400908 error = updateStorage();
909 if (error.isError())
910 {
911 return error;
912 }
913
914 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700915}
916
Geoff Langef7b0162014-09-04 13:29:23 -0400917gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700918{
919 GLsizei width = getBaseLevelWidth();
920 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400921 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700922
923 ASSERT(width > 0 && height > 0);
924
925 // use existing storage level count, when previously specified by TexStorage*D
926 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
927
Geoff Langef7b0162014-09-04 13:29:23 -0400928 // TODO(geofflang): Determine if the texture creation succeeded
929 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
930
931 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700932}
933
Geoff Langef7b0162014-09-04 13:29:23 -0400934gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700935{
Geoff Langef7b0162014-09-04 13:29:23 -0400936 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700937 {
Geoff Langef7b0162014-09-04 13:29:23 -0400938 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700939 {
Geoff Langef7b0162014-09-04 13:29:23 -0400940 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
941 if (error.isError())
942 {
943 return error;
944 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700945 }
946 }
947
Geoff Langef7b0162014-09-04 13:29:23 -0400948 SafeDelete(mTexStorage);
949 mTexStorage = newCompleteTexStorage;
950
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700951 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400952
953 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700954}
955
Geoff Langef7b0162014-09-04 13:29:23 -0400956gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700957{
958 ASSERT(mTexStorage != NULL);
959 GLint storageLevels = mTexStorage->getLevelCount();
960 for (int level = 0; level < storageLevels; level++)
961 {
962 if (mImageArray[level]->isDirty() && isLevelComplete(level))
963 {
Geoff Langef7b0162014-09-04 13:29:23 -0400964 gl::Error error = updateStorageLevel(level);
965 if (error.isError())
966 {
967 return error;
968 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700969 }
970 }
Geoff Langef7b0162014-09-04 13:29:23 -0400971
972 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700973}
974
Geoff Langef7b0162014-09-04 13:29:23 -0400975gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700976{
977 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
978 ASSERT(isLevelComplete(level));
979
980 if (mImageArray[level]->isDirty())
981 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400982 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
983 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -0400984 gl::Error error = commitRegion(index, region);
985 if (error.isError())
986 {
987 return error;
988 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700989 }
Geoff Langef7b0162014-09-04 13:29:23 -0400990
991 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700992}
993
994void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
995{
996 // If there currently is a corresponding storage texture image, it has these parameters
997 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
998 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
999 const GLenum storageFormat = getBaseLevelInternalFormat();
1000
1001 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1002
1003 if (mTexStorage)
1004 {
1005 const int storageLevels = mTexStorage->getLevelCount();
1006
1007 if ((level >= storageLevels && storageLevels != 0) ||
1008 width != storageWidth ||
1009 height != storageHeight ||
1010 internalformat != storageFormat) // Discard mismatched storage
1011 {
1012 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1013 {
1014 mImageArray[i]->markDirty();
1015 }
1016
1017 SafeDelete(mTexStorage);
1018 mDirtyImages = true;
1019 }
1020 }
1021}
1022
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001023gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001024{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001025 ASSERT(!index.hasLayer());
1026 GLint level = index.mipIndex;
1027
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001028 if (isValidLevel(level))
1029 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001030 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001031 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001032 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001033 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001034 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001035 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001036
1037 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001038 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001039
1040 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001041}
1042
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001043gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1044{
1045 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1046}
Brandon Jones0511e802014-07-14 16:27:26 -07001047
Jamie Madillcb83dc12014-09-29 10:46:12 -04001048gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1049{
1050 // "layer" does not apply to 2D Textures.
1051 return gl::ImageIndex::Make2D(mip);
1052}
1053
Brandon Jones78b1acd2014-07-15 15:33:07 -07001054TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001055 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001056{
1057 for (int i = 0; i < 6; i++)
1058 {
1059 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1060 {
1061 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1062 }
1063 }
1064}
1065
1066TextureD3D_Cube::~TextureD3D_Cube()
1067{
Austin Kinross69822602014-08-12 15:51:37 -07001068 // Delete the Images before the TextureStorage.
1069 // Images might be relying on the TextureStorage for some of their data.
1070 // 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 -07001071 for (int i = 0; i < 6; i++)
1072 {
1073 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1074 {
1075 SafeDelete(mImageArray[i][j]);
1076 }
1077 }
Austin Kinross69822602014-08-12 15:51:37 -07001078
1079 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001080}
1081
Brandon Jonescef06ff2014-08-05 13:27:48 -07001082Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001083{
1084 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001085 ASSERT(layer < 6);
1086 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001087}
1088
Jamie Madillfeda4d22014-09-17 13:03:29 -04001089Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1090{
1091 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1092 ASSERT(index.layerIndex < 6);
1093 return mImageArray[index.layerIndex][index.mipIndex];
1094}
1095
Brandon Jonescef06ff2014-08-05 13:27:48 -07001096GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001097{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001098 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1099 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001100}
1101
Brandon Jonescef06ff2014-08-05 13:27:48 -07001102GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001103{
1104 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001105 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001106 else
1107 return GL_NONE;
1108}
1109
Brandon Jonescef06ff2014-08-05 13:27:48 -07001110bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001111{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001112 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001113}
1114
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001115gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1116 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1117 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001118{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001119 ASSERT(depth == 1);
1120
Geoff Lang5d601382014-07-22 15:14:06 -04001121 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001122 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001123
Jamie Madillba6bc952014-10-06 10:56:22 -04001124 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001125
Jamie Madillba6bc952014-10-06 10:56:22 -04001126 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001127}
1128
Geoff Langb5348332014-09-02 13:16:34 -04001129gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1130 GLsizei width, GLsizei height, GLsizei depth,
1131 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001133 ASSERT(depth == 1);
1134
Brandon Jones0511e802014-07-14 16:27:26 -07001135 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001136 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1137
Brandon Jones0511e802014-07-14 16:27:26 -07001138 redefineImage(faceIndex, level, format, width, height);
1139
Geoff Langb5348332014-09-02 13:16:34 -04001140 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001141}
1142
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001143gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1144 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1145 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001146{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001147 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001148 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001149 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001150}
1151
Geoff Langb5348332014-09-02 13:16:34 -04001152gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1153 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1154 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001155{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001156 ASSERT(depth == 1 && zoffset == 0);
1157
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001158 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001159
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001160 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -04001161 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001162 {
Geoff Langb5348332014-09-02 13:16:34 -04001163 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001164 }
Geoff Langb5348332014-09-02 13:16:34 -04001165
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001166 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1167 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001168}
1169
Geoff Langef7b0162014-09-04 13:29:23 -04001170gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1171 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001172{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001173 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001174 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1175
Brandon Jones0511e802014-07-14 16:27:26 -07001176 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1177
Jamie Madill82bf0c52014-10-03 11:50:53 -04001178 gl::Rectangle sourceRect(x, y, width, height);
1179
Brandon Jones0511e802014-07-14 16:27:26 -07001180 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1181 {
Geoff Langef7b0162014-09-04 13:29:23 -04001182 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1183 if (error.isError())
1184 {
1185 return error;
1186 }
1187
Brandon Jones0511e802014-07-14 16:27:26 -07001188 mDirtyImages = true;
1189 }
1190 else
1191 {
Geoff Langef7b0162014-09-04 13:29:23 -04001192 gl::Error error = ensureRenderTarget();
1193 if (error.isError())
1194 {
1195 return error;
1196 }
1197
Brandon Jones0511e802014-07-14 16:27:26 -07001198 mImageArray[faceIndex][level]->markClean();
1199
1200 ASSERT(width == height);
1201
1202 if (width > 0 && isValidFaceLevel(faceIndex, level))
1203 {
Geoff Langef7b0162014-09-04 13:29:23 -04001204 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1205 if (error.isError())
1206 {
1207 return error;
1208 }
Brandon Jones0511e802014-07-14 16:27:26 -07001209 }
1210 }
Geoff Langef7b0162014-09-04 13:29:23 -04001211
1212 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001213}
1214
Geoff Langef7b0162014-09-04 13:29:23 -04001215gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1216 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001217{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001218 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001219
1220 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1221 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1222 // rely on the "getBaseLevel*" methods reliably otherwise.
1223 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1224
Jamie Madill82bf0c52014-10-03 11:50:53 -04001225 gl::Rectangle sourceRect(x, y, width, height);
1226
Brandon Jones0511e802014-07-14 16:27:26 -07001227 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1228 {
Geoff Langef7b0162014-09-04 13:29:23 -04001229 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1230 if (error.isError())
1231 {
1232 return error;
1233 }
1234
Brandon Jones0511e802014-07-14 16:27:26 -07001235 mDirtyImages = true;
1236 }
1237 else
1238 {
Geoff Langef7b0162014-09-04 13:29:23 -04001239 gl::Error error = ensureRenderTarget();
1240 if (error.isError())
1241 {
1242 return error;
1243 }
Brandon Jones0511e802014-07-14 16:27:26 -07001244
1245 if (isValidFaceLevel(faceIndex, level))
1246 {
Geoff Langef7b0162014-09-04 13:29:23 -04001247 error = updateStorageFaceLevel(faceIndex, level);
1248 if (error.isError())
1249 {
1250 return error;
1251 }
Brandon Jones0511e802014-07-14 16:27:26 -07001252
Geoff Langef7b0162014-09-04 13:29:23 -04001253 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1254 xoffset, yoffset, mTexStorage, target, level);
1255 if (error.isError())
1256 {
1257 return error;
1258 }
Brandon Jones0511e802014-07-14 16:27:26 -07001259 }
1260 }
Geoff Langef7b0162014-09-04 13:29:23 -04001261
1262 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001263}
1264
Geoff Lang1f8532b2014-09-05 09:46:13 -04001265gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001266{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001267 ASSERT(width == height);
1268 ASSERT(depth == 1);
1269
Brandon Jones0511e802014-07-14 16:27:26 -07001270 for (int level = 0; level < levels; level++)
1271 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001272 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001273 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1274 {
1275 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1276 }
1277 }
1278
1279 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1280 {
1281 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1282 {
1283 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1284 }
1285 }
1286
Geoff Lang1f8532b2014-09-05 09:46:13 -04001287 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001288 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001289 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001290
1291 gl::Error error = setCompleteTexStorage(storage);
1292 if (error.isError())
1293 {
1294 SafeDelete(storage);
1295 return error;
1296 }
1297
1298 mImmutable = true;
1299
1300 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001301}
1302
Brandon Jones0511e802014-07-14 16:27:26 -07001303// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1304bool TextureD3D_Cube::isCubeComplete() const
1305{
1306 int baseWidth = getBaseLevelWidth();
1307 int baseHeight = getBaseLevelHeight();
1308 GLenum baseFormat = getBaseLevelInternalFormat();
1309
1310 if (baseWidth <= 0 || baseWidth != baseHeight)
1311 {
1312 return false;
1313 }
1314
1315 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1316 {
1317 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1318
1319 if (faceBaseImage.getWidth() != baseWidth ||
1320 faceBaseImage.getHeight() != baseHeight ||
1321 faceBaseImage.getInternalFormat() != baseFormat )
1322 {
1323 return false;
1324 }
1325 }
1326
1327 return true;
1328}
1329
Brandon Jones6053a522014-07-25 16:22:09 -07001330void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1331{
1332 UNREACHABLE();
1333}
1334
1335void TextureD3D_Cube::releaseTexImage()
1336{
1337 UNREACHABLE();
1338}
1339
1340
Jamie Madill4aa79e12014-09-29 10:46:14 -04001341void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001342{
1343 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1344 int levelCount = mipLevels();
1345 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1346 {
1347 for (int level = 1; level < levelCount; level++)
1348 {
1349 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1350 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1351 }
1352 }
Brandon Jones0511e802014-07-14 16:27:26 -07001353}
1354
Jamie Madillac7579c2014-09-17 16:59:33 -04001355unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001356{
Geoff Langef7b0162014-09-04 13:29:23 -04001357 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001358}
1359
Geoff Lang64f23f62014-09-10 14:40:12 -04001360gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001361{
Jamie Madillac7579c2014-09-17 16:59:33 -04001362 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001363
1364 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001365 gl::Error error = ensureRenderTarget();
1366 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001367 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001368 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001369 }
1370
Geoff Langef7b0162014-09-04 13:29:23 -04001371 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1372 if (error.isError())
1373 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001374 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001375 }
1376
Geoff Lang64f23f62014-09-10 14:40:12 -04001377 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001378}
1379
Geoff Langef7b0162014-09-04 13:29:23 -04001380gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001381{
1382 // Only initialize the first time this texture is used as a render target or shader resource
1383 if (mTexStorage)
1384 {
Geoff Langef7b0162014-09-04 13:29:23 -04001385 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001386 }
1387
1388 // do not attempt to create storage for nonexistant data
1389 if (!isFaceLevelComplete(0, 0))
1390 {
Geoff Langef7b0162014-09-04 13:29:23 -04001391 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001392 }
1393
1394 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1395
Geoff Langef7b0162014-09-04 13:29:23 -04001396 TextureStorage *storage = NULL;
1397 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1398 if (error.isError())
1399 {
1400 return error;
1401 }
1402
1403 error = setCompleteTexStorage(storage);
1404 if (error.isError())
1405 {
1406 SafeDelete(storage);
1407 return error;
1408 }
1409
Brandon Jones0511e802014-07-14 16:27:26 -07001410 ASSERT(mTexStorage);
1411
1412 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001413 error = updateStorage();
1414 if (error.isError())
1415 {
1416 return error;
1417 }
1418
1419 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001420}
1421
Geoff Langef7b0162014-09-04 13:29:23 -04001422gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001423{
1424 GLsizei size = getBaseLevelWidth();
1425
1426 ASSERT(size > 0);
1427
1428 // use existing storage level count, when previously specified by TexStorage*D
1429 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1430
Geoff Langef7b0162014-09-04 13:29:23 -04001431 // TODO (geofflang): detect if storage creation succeeded
1432 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1433
1434 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001435}
1436
Geoff Langef7b0162014-09-04 13:29:23 -04001437gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001438{
Geoff Langef7b0162014-09-04 13:29:23 -04001439 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001440 {
1441 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1442 {
Geoff Langef7b0162014-09-04 13:29:23 -04001443 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001444 {
Geoff Langef7b0162014-09-04 13:29:23 -04001445 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1446 if (error.isError())
1447 {
1448 return error;
1449 }
Brandon Jones0511e802014-07-14 16:27:26 -07001450 }
1451 }
1452 }
1453
Geoff Langef7b0162014-09-04 13:29:23 -04001454 SafeDelete(mTexStorage);
1455 mTexStorage = newCompleteTexStorage;
1456
Brandon Jones0511e802014-07-14 16:27:26 -07001457 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001458 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001459}
1460
Geoff Langef7b0162014-09-04 13:29:23 -04001461gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001462{
1463 ASSERT(mTexStorage != NULL);
1464 GLint storageLevels = mTexStorage->getLevelCount();
1465 for (int face = 0; face < 6; face++)
1466 {
1467 for (int level = 0; level < storageLevels; level++)
1468 {
1469 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1470 {
Geoff Langef7b0162014-09-04 13:29:23 -04001471 gl::Error error = updateStorageFaceLevel(face, level);
1472 if (error.isError())
1473 {
1474 return error;
1475 }
Brandon Jones0511e802014-07-14 16:27:26 -07001476 }
1477 }
1478 }
Geoff Langef7b0162014-09-04 13:29:23 -04001479
1480 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001481}
1482
Brandon Jones0511e802014-07-14 16:27:26 -07001483bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1484{
1485 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1486}
1487
Brandon Jones0511e802014-07-14 16:27:26 -07001488bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1489{
1490 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1491
1492 if (isImmutable())
1493 {
1494 return true;
1495 }
1496
1497 int baseSize = getBaseLevelWidth();
1498
1499 if (baseSize <= 0)
1500 {
1501 return false;
1502 }
1503
1504 // "isCubeComplete" checks for base level completeness and we must call that
1505 // to determine if any face at level 0 is complete. We omit that check here
1506 // to avoid re-checking cube-completeness for every face at level 0.
1507 if (level == 0)
1508 {
1509 return true;
1510 }
1511
1512 // Check that non-zero levels are consistent with the base level.
1513 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1514
1515 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1516 {
1517 return false;
1518 }
1519
1520 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1521 {
1522 return false;
1523 }
1524
1525 return true;
1526}
1527
Geoff Langef7b0162014-09-04 13:29:23 -04001528gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001529{
1530 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1531 ImageD3D *image = mImageArray[faceIndex][level];
1532
1533 if (image->isDirty())
1534 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001535 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1536 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1537 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001538 gl::Error error = commitRegion(index, region);
1539 if (error.isError())
1540 {
1541 return error;
1542 }
Brandon Jones0511e802014-07-14 16:27:26 -07001543 }
Geoff Langef7b0162014-09-04 13:29:23 -04001544
1545 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001546}
1547
1548void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1549{
1550 // If there currently is a corresponding storage texture image, it has these parameters
1551 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1552 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1553 const GLenum storageFormat = getBaseLevelInternalFormat();
1554
1555 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1556
1557 if (mTexStorage)
1558 {
1559 const int storageLevels = mTexStorage->getLevelCount();
1560
1561 if ((level >= storageLevels && storageLevels != 0) ||
1562 width != storageWidth ||
1563 height != storageHeight ||
1564 internalformat != storageFormat) // Discard mismatched storage
1565 {
1566 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1567 {
1568 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1569 {
1570 mImageArray[faceIndex][level]->markDirty();
1571 }
1572 }
1573
1574 SafeDelete(mTexStorage);
1575
1576 mDirtyImages = true;
1577 }
1578 }
1579}
1580
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001581gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001582{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001583 ASSERT(index.hasLayer());
1584
1585 GLint level = index.mipIndex;
1586 int faceIndex = static_cast<int>(index.layerIndex);
1587
Brandon Jones0511e802014-07-14 16:27:26 -07001588 if (isValidFaceLevel(faceIndex, level))
1589 {
1590 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001591 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001592 if (error.isError())
1593 {
1594 return error;
1595 }
1596
1597 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001598 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001599
1600 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001601}
1602
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001603gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1604{
1605 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1606}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001607
Jamie Madillcb83dc12014-09-29 10:46:12 -04001608gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1609{
1610 // The "layer" of the image index corresponds to the cube face
1611 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1612}
1613
Brandon Jones78b1acd2014-07-15 15:33:07 -07001614TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001615 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616{
1617 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1618 {
1619 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1620 }
1621}
1622
1623TextureD3D_3D::~TextureD3D_3D()
1624{
Austin Kinross69822602014-08-12 15:51:37 -07001625 // Delete the Images before the TextureStorage.
1626 // Images might be relying on the TextureStorage for some of their data.
1627 // 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 -07001628 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1629 {
1630 delete mImageArray[i];
1631 }
Austin Kinross69822602014-08-12 15:51:37 -07001632
1633 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634}
1635
Brandon Jonescef06ff2014-08-05 13:27:48 -07001636Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001637{
1638 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001639 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001640 return mImageArray[level];
1641}
1642
Jamie Madillfeda4d22014-09-17 13:03:29 -04001643Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1644{
1645 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001646 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001647 ASSERT(index.type == GL_TEXTURE_3D);
1648 return mImageArray[index.mipIndex];
1649}
1650
Brandon Jonescef06ff2014-08-05 13:27:48 -07001651GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001653 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1654 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001655}
1656
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657GLsizei TextureD3D_3D::getWidth(GLint level) const
1658{
1659 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1660 return mImageArray[level]->getWidth();
1661 else
1662 return 0;
1663}
1664
1665GLsizei TextureD3D_3D::getHeight(GLint level) const
1666{
1667 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1668 return mImageArray[level]->getHeight();
1669 else
1670 return 0;
1671}
1672
1673GLsizei TextureD3D_3D::getDepth(GLint level) const
1674{
1675 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1676 return mImageArray[level]->getDepth();
1677 else
1678 return 0;
1679}
1680
1681GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1682{
1683 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1684 return mImageArray[level]->getInternalFormat();
1685 else
1686 return GL_NONE;
1687}
1688
1689bool TextureD3D_3D::isDepth(GLint level) const
1690{
Geoff Lang5d601382014-07-22 15:14:06 -04001691 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001692}
1693
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001694gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1695 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1696 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001698 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001699 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1700
Brandon Jones78b1acd2014-07-15 15:33:07 -07001701 redefineImage(level, sizedInternalFormat, width, height, depth);
1702
1703 bool fastUnpacked = false;
1704
Jamie Madillba6bc952014-10-06 10:56:22 -04001705 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1706
Brandon Jones78b1acd2014-07-15 15:33:07 -07001707 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1708 if (isFastUnpackable(unpack, sizedInternalFormat))
1709 {
1710 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001711 RenderTarget *destRenderTarget = NULL;
1712 gl::Error error = getRenderTarget(index, &destRenderTarget);
1713 if (error.isError())
1714 {
1715 return error;
1716 }
1717
Brandon Jones78b1acd2014-07-15 15:33:07 -07001718 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1719
Geoff Lang64f23f62014-09-10 14:40:12 -04001720 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1721 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001722 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001723 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001724 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001725
1726 // Ensure we don't overwrite our newly initialized data
1727 mImageArray[level]->markClean();
1728
1729 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001730 }
1731
1732 if (!fastUnpacked)
1733 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001734 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001735 if (error.isError())
1736 {
1737 return error;
1738 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001740
1741 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001742}
1743
Geoff Langb5348332014-09-02 13:16:34 -04001744gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1745 GLsizei width, GLsizei height,GLsizei depth,
1746 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001747{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001748 ASSERT(target == GL_TEXTURE_3D);
1749
Brandon Jones78b1acd2014-07-15 15:33:07 -07001750 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1751 redefineImage(level, format, width, height, depth);
1752
Geoff Langb5348332014-09-02 13:16:34 -04001753 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001754}
1755
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001756gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1757 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1758 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001759{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001760 ASSERT(target == GL_TEXTURE_3D);
1761
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762 bool fastUnpacked = false;
1763
Jamie Madillac7579c2014-09-17 16:59:33 -04001764 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1765
Brandon Jones78b1acd2014-07-15 15:33:07 -07001766 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1767 if (isFastUnpackable(unpack, getInternalFormat(level)))
1768 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001769 RenderTarget *destRenderTarget = NULL;
1770 gl::Error error = getRenderTarget(index, &destRenderTarget);
1771 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001772 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001773 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001774 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001775
1776 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1777 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1778 if (error.isError())
1779 {
1780 return error;
1781 }
1782
1783 // Ensure we don't overwrite our newly initialized data
1784 mImageArray[level]->markClean();
1785
1786 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001787 }
1788
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001789 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001790 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001791 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1792 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001793 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001794
1795 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001796}
1797
Geoff Langb5348332014-09-02 13:16:34 -04001798gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1799 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1800 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001801{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001802 ASSERT(target == GL_TEXTURE_3D);
1803
Geoff Langb5348332014-09-02 13:16:34 -04001804 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1805 format, imageSize, pixels, mImageArray[level]);
1806 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001807 {
Geoff Langb5348332014-09-02 13:16:34 -04001808 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 }
Geoff Langb5348332014-09-02 13:16:34 -04001810
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001811 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1812 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1813 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001814}
1815
Geoff Langef7b0162014-09-04 13:29:23 -04001816gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1817 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001818{
1819 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001820 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001821}
1822
Geoff Langef7b0162014-09-04 13:29:23 -04001823gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1824 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001825{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001826 ASSERT(target == GL_TEXTURE_3D);
1827
Brandon Jones78b1acd2014-07-15 15:33:07 -07001828 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1829 // the current level we're copying to is defined (with appropriate format, width & height)
1830 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1831
Jamie Madill82bf0c52014-10-03 11:50:53 -04001832 gl::Rectangle sourceRect(x, y, width, height);
1833
Brandon Jones78b1acd2014-07-15 15:33:07 -07001834 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1835 {
Geoff Langef7b0162014-09-04 13:29:23 -04001836 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1837 if (error.isError())
1838 {
1839 return error;
1840 }
1841
Brandon Jones78b1acd2014-07-15 15:33:07 -07001842 mDirtyImages = true;
1843 }
1844 else
1845 {
Geoff Langef7b0162014-09-04 13:29:23 -04001846 gl::Error error = ensureRenderTarget();
1847 if (error.isError())
1848 {
1849 return error;
1850 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001851
1852 if (isValidLevel(level))
1853 {
Geoff Langef7b0162014-09-04 13:29:23 -04001854 error = updateStorageLevel(level);
1855 if (error.isError())
1856 {
1857 return error;
1858 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001859
Geoff Langef7b0162014-09-04 13:29:23 -04001860 error = mRenderer->copyImage3D(source, sourceRect,
1861 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1862 xoffset, yoffset, zoffset, mTexStorage, level);
1863 if (error.isError())
1864 {
1865 return error;
1866 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001867 }
1868 }
Geoff Langef7b0162014-09-04 13:29:23 -04001869
1870 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001871}
1872
Geoff Lang1f8532b2014-09-05 09:46:13 -04001873gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001874{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001875 ASSERT(target == GL_TEXTURE_3D);
1876
Brandon Jones78b1acd2014-07-15 15:33:07 -07001877 for (int level = 0; level < levels; level++)
1878 {
1879 GLsizei levelWidth = std::max(1, width >> level);
1880 GLsizei levelHeight = std::max(1, height >> level);
1881 GLsizei levelDepth = std::max(1, depth >> level);
1882 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1883 }
1884
1885 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1886 {
1887 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1888 }
1889
Geoff Lang1f8532b2014-09-05 09:46:13 -04001890 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001891 bool renderTarget = IsRenderTargetUsage(mUsage);
1892 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001893
1894 gl::Error error = setCompleteTexStorage(storage);
1895 if (error.isError())
1896 {
1897 SafeDelete(storage);
1898 return error;
1899 }
1900
1901 mImmutable = true;
1902
1903 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001904}
1905
Brandon Jones6053a522014-07-25 16:22:09 -07001906void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001907{
Brandon Jones6053a522014-07-25 16:22:09 -07001908 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909}
1910
Brandon Jones6053a522014-07-25 16:22:09 -07001911void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001912{
Brandon Jones6053a522014-07-25 16:22:09 -07001913 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001914}
1915
Brandon Jones6053a522014-07-25 16:22:09 -07001916
Jamie Madill4aa79e12014-09-29 10:46:14 -04001917void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001918{
1919 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1920 int levelCount = mipLevels();
1921 for (int level = 1; level < levelCount; level++)
1922 {
1923 redefineImage(level, getBaseLevelInternalFormat(),
1924 std::max(getBaseLevelWidth() >> level, 1),
1925 std::max(getBaseLevelHeight() >> level, 1),
1926 std::max(getBaseLevelDepth() >> level, 1));
1927 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001928}
1929
Jamie Madillac7579c2014-09-17 16:59:33 -04001930unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001931{
Geoff Langef7b0162014-09-04 13:29:23 -04001932 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001933}
1934
Geoff Lang64f23f62014-09-10 14:40:12 -04001935gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001936{
1937 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001938 gl::Error error = ensureRenderTarget();
1939 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001940 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001941 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001942 }
1943
Jamie Madillac7579c2014-09-17 16:59:33 -04001944 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001945 {
Geoff Langef7b0162014-09-04 13:29:23 -04001946 error = updateStorage();
1947 if (error.isError())
1948 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001949 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001950 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001951 }
1952 else
1953 {
Geoff Langef7b0162014-09-04 13:29:23 -04001954 error = updateStorageLevel(index.mipIndex);
1955 if (error.isError())
1956 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001957 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001958 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001959 }
1960
Geoff Lang64f23f62014-09-10 14:40:12 -04001961 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001962}
1963
Geoff Langef7b0162014-09-04 13:29:23 -04001964gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001965{
1966 // Only initialize the first time this texture is used as a render target or shader resource
1967 if (mTexStorage)
1968 {
Geoff Langef7b0162014-09-04 13:29:23 -04001969 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001970 }
1971
1972 // do not attempt to create storage for nonexistant data
1973 if (!isLevelComplete(0))
1974 {
Geoff Langef7b0162014-09-04 13:29:23 -04001975 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001976 }
1977
1978 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1979
Geoff Langef7b0162014-09-04 13:29:23 -04001980 rx::TextureStorage *storage = NULL;
1981 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1982 if (error.isError())
1983 {
1984 return error;
1985 }
1986
1987 error = setCompleteTexStorage(storage);
1988 if (error.isError())
1989 {
1990 SafeDelete(storage);
1991 return error;
1992 }
1993
Brandon Jones78b1acd2014-07-15 15:33:07 -07001994 ASSERT(mTexStorage);
1995
1996 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001997 error = updateStorage();
1998 if (error.isError())
1999 {
2000 return error;
2001 }
2002
2003 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002004}
2005
Geoff Langef7b0162014-09-04 13:29:23 -04002006gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002007{
2008 GLsizei width = getBaseLevelWidth();
2009 GLsizei height = getBaseLevelHeight();
2010 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002011 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002012
2013 ASSERT(width > 0 && height > 0 && depth > 0);
2014
2015 // use existing storage level count, when previously specified by TexStorage*D
2016 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2017
Geoff Langef7b0162014-09-04 13:29:23 -04002018 // TODO: Verify creation of the storage succeeded
2019 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2020
2021 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002022}
2023
Geoff Langef7b0162014-09-04 13:29:23 -04002024gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002025{
2026 SafeDelete(mTexStorage);
2027 mTexStorage = newCompleteTexStorage;
2028 mDirtyImages = true;
2029
2030 // We do not support managed 3D storage, as that is D3D9/ES2-only
2031 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002032
2033 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002034}
2035
Geoff Langef7b0162014-09-04 13:29:23 -04002036gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002037{
2038 ASSERT(mTexStorage != NULL);
2039 GLint storageLevels = mTexStorage->getLevelCount();
2040 for (int level = 0; level < storageLevels; level++)
2041 {
2042 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2043 {
Geoff Langef7b0162014-09-04 13:29:23 -04002044 gl::Error error = updateStorageLevel(level);
2045 if (error.isError())
2046 {
2047 return error;
2048 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002049 }
2050 }
Geoff Langef7b0162014-09-04 13:29:23 -04002051
2052 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002053}
2054
Brandon Jones78b1acd2014-07-15 15:33:07 -07002055bool TextureD3D_3D::isValidLevel(int level) const
2056{
2057 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2058}
2059
2060bool TextureD3D_3D::isLevelComplete(int level) const
2061{
2062 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2063
2064 if (isImmutable())
2065 {
2066 return true;
2067 }
2068
2069 GLsizei width = getBaseLevelWidth();
2070 GLsizei height = getBaseLevelHeight();
2071 GLsizei depth = getBaseLevelDepth();
2072
2073 if (width <= 0 || height <= 0 || depth <= 0)
2074 {
2075 return false;
2076 }
2077
2078 if (level == 0)
2079 {
2080 return true;
2081 }
2082
2083 ImageD3D *levelImage = mImageArray[level];
2084
2085 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2086 {
2087 return false;
2088 }
2089
2090 if (levelImage->getWidth() != std::max(1, width >> level))
2091 {
2092 return false;
2093 }
2094
2095 if (levelImage->getHeight() != std::max(1, height >> level))
2096 {
2097 return false;
2098 }
2099
2100 if (levelImage->getDepth() != std::max(1, depth >> level))
2101 {
2102 return false;
2103 }
2104
2105 return true;
2106}
2107
Geoff Langef7b0162014-09-04 13:29:23 -04002108gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002109{
2110 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2111 ASSERT(isLevelComplete(level));
2112
2113 if (mImageArray[level]->isDirty())
2114 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002115 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2116 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002117 gl::Error error = commitRegion(index, region);
2118 if (error.isError())
2119 {
2120 return error;
2121 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002122 }
Geoff Langef7b0162014-09-04 13:29:23 -04002123
2124 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002125}
2126
2127void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2128{
2129 // If there currently is a corresponding storage texture image, it has these parameters
2130 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2131 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2132 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2133 const GLenum storageFormat = getBaseLevelInternalFormat();
2134
2135 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2136
2137 if (mTexStorage)
2138 {
2139 const int storageLevels = mTexStorage->getLevelCount();
2140
2141 if ((level >= storageLevels && storageLevels != 0) ||
2142 width != storageWidth ||
2143 height != storageHeight ||
2144 depth != storageDepth ||
2145 internalformat != storageFormat) // Discard mismatched storage
2146 {
2147 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2148 {
2149 mImageArray[i]->markDirty();
2150 }
2151
2152 SafeDelete(mTexStorage);
2153 mDirtyImages = true;
2154 }
2155 }
2156}
2157
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002158gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002159{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002160 ASSERT(!index.hasLayer());
2161 GLint level = index.mipIndex;
2162
Brandon Jones78b1acd2014-07-15 15:33:07 -07002163 if (isValidLevel(level))
2164 {
2165 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04002166 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002167 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002168 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002169 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002170 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002171
2172 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002173 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002174
2175 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002176}
2177
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002178gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2179{
2180 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2181 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2182}
Brandon Jones142ec422014-07-16 10:31:30 -07002183
Jamie Madillcb83dc12014-09-29 10:46:12 -04002184gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2185{
2186 // The "layer" here does not apply to 3D images. We use one Image per mip.
2187 return gl::ImageIndex::Make3D(mip);
2188}
2189
Brandon Jones142ec422014-07-16 10:31:30 -07002190TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002191 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002192{
2193 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2194 {
2195 mLayerCounts[level] = 0;
2196 mImageArray[level] = NULL;
2197 }
2198}
2199
2200TextureD3D_2DArray::~TextureD3D_2DArray()
2201{
Austin Kinross69822602014-08-12 15:51:37 -07002202 // Delete the Images before the TextureStorage.
2203 // Images might be relying on the TextureStorage for some of their data.
2204 // 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 -07002205 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002206 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002207}
2208
Brandon Jones142ec422014-07-16 10:31:30 -07002209Image *TextureD3D_2DArray::getImage(int level, int layer) const
2210{
2211 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2212 ASSERT(layer < mLayerCounts[level]);
2213 return mImageArray[level][layer];
2214}
2215
Jamie Madillfeda4d22014-09-17 13:03:29 -04002216Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2217{
2218 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2219 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2220 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2221 return mImageArray[index.mipIndex][index.layerIndex];
2222}
2223
Brandon Jones142ec422014-07-16 10:31:30 -07002224GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2225{
2226 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2227 return mLayerCounts[level];
2228}
2229
Brandon Jones142ec422014-07-16 10:31:30 -07002230GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2231{
2232 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2233}
2234
2235GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2236{
2237 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2238}
2239
Brandon Jones142ec422014-07-16 10:31:30 -07002240GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2241{
2242 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2243}
2244
2245bool TextureD3D_2DArray::isDepth(GLint level) const
2246{
Geoff Lang5d601382014-07-22 15:14:06 -04002247 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002248}
2249
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002250gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2251 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2252 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002253{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002254 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2255
Geoff Lang5d601382014-07-22 15:14:06 -04002256 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2257
Brandon Jones142ec422014-07-16 10:31:30 -07002258 redefineImage(level, sizedInternalFormat, width, height, depth);
2259
Geoff Lang5d601382014-07-22 15:14:06 -04002260 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2261 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002262
2263 for (int i = 0; i < depth; i++)
2264 {
2265 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002266 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2267 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002268 if (error.isError())
2269 {
2270 return error;
2271 }
Brandon Jones142ec422014-07-16 10:31:30 -07002272 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002273
2274 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002275}
2276
Geoff Langb5348332014-09-02 13:16:34 -04002277gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2278 GLsizei width, GLsizei height, GLsizei depth,
2279 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002280{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002281 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2282
Brandon Jones142ec422014-07-16 10:31:30 -07002283 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2284 redefineImage(level, format, width, height, depth);
2285
Geoff Lang5d601382014-07-22 15:14:06 -04002286 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2287 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002288
2289 for (int i = 0; i < depth; i++)
2290 {
2291 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002292 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2293 if (error.isError())
2294 {
2295 return error;
2296 }
Brandon Jones142ec422014-07-16 10:31:30 -07002297 }
Geoff Langb5348332014-09-02 13:16:34 -04002298
2299 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002300}
2301
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002302gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2303 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2304 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002305{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002306 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2307
Geoff Lang5d601382014-07-22 15:14:06 -04002308 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
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 int layer = zoffset + i;
2314 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2315
Jamie Madillfeda4d22014-09-17 13:03:29 -04002316 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002317 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2318 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002319 if (error.isError())
2320 {
2321 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002322 }
2323 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002324
2325 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002326}
2327
Geoff Langb5348332014-09-02 13:16:34 -04002328gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2329 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2330 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002331{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002332 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2333
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 int layer = zoffset + i;
2340 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2341
Geoff Langb5348332014-09-02 13:16:34 -04002342 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2343 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002344 {
Geoff Langb5348332014-09-02 13:16:34 -04002345 return error;
2346 }
2347
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002348 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2349 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2350 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002351 if (error.isError())
2352 {
2353 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002354 }
2355 }
Geoff Langb5348332014-09-02 13:16:34 -04002356
2357 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002358}
2359
Geoff Langef7b0162014-09-04 13:29:23 -04002360gl::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 -07002361{
2362 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002363 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002364}
2365
Geoff Langef7b0162014-09-04 13:29:23 -04002366gl::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 -07002367{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002368 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2369
Brandon Jones142ec422014-07-16 10:31:30 -07002370 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2371 // the current level we're copying to is defined (with appropriate format, width & height)
2372 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2373
Jamie Madill82bf0c52014-10-03 11:50:53 -04002374 gl::Rectangle sourceRect(x, y, width, height);
2375
Brandon Jones142ec422014-07-16 10:31:30 -07002376 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2377 {
Geoff Langef7b0162014-09-04 13:29:23 -04002378 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2379 if (error.isError())
2380 {
2381 return error;
2382 }
2383
Brandon Jones142ec422014-07-16 10:31:30 -07002384 mDirtyImages = true;
2385 }
2386 else
2387 {
Geoff Langef7b0162014-09-04 13:29:23 -04002388 gl::Error error = ensureRenderTarget();
2389 if (error.isError())
2390 {
2391 return error;
2392 }
Brandon Jones142ec422014-07-16 10:31:30 -07002393
2394 if (isValidLevel(level))
2395 {
Geoff Langef7b0162014-09-04 13:29:23 -04002396 error = updateStorageLevel(level);
2397 if (error.isError())
2398 {
2399 return error;
2400 }
Brandon Jones142ec422014-07-16 10:31:30 -07002401
Geoff Langef7b0162014-09-04 13:29:23 -04002402 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2403 xoffset, yoffset, zoffset, mTexStorage, level);
2404 if (error.isError())
2405 {
2406 return error;
2407 }
Brandon Jones142ec422014-07-16 10:31:30 -07002408 }
2409 }
Geoff Langef7b0162014-09-04 13:29:23 -04002410 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002411}
2412
Geoff Lang1f8532b2014-09-05 09:46:13 -04002413gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002414{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002415 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2416
Brandon Jones142ec422014-07-16 10:31:30 -07002417 deleteImages();
2418
2419 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2420 {
2421 GLsizei levelWidth = std::max(1, width >> level);
2422 GLsizei levelHeight = std::max(1, height >> level);
2423
2424 mLayerCounts[level] = (level < levels ? depth : 0);
2425
2426 if (mLayerCounts[level] > 0)
2427 {
2428 // Create new images for this level
2429 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2430
2431 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2432 {
2433 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2434 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2435 levelHeight, 1, true);
2436 }
2437 }
2438 }
2439
Geoff Lang1f8532b2014-09-05 09:46:13 -04002440 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002441 bool renderTarget = IsRenderTargetUsage(mUsage);
2442 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002443
2444 gl::Error error = setCompleteTexStorage(storage);
2445 if (error.isError())
2446 {
2447 SafeDelete(storage);
2448 return error;
2449 }
2450
2451 mImmutable = true;
2452
2453 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002454}
2455
Brandon Jones6053a522014-07-25 16:22:09 -07002456void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002457{
Brandon Jones6053a522014-07-25 16:22:09 -07002458 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002459}
2460
Brandon Jones6053a522014-07-25 16:22:09 -07002461void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002462{
Brandon Jones6053a522014-07-25 16:22:09 -07002463 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002464}
2465
Brandon Jones6053a522014-07-25 16:22:09 -07002466
Jamie Madill4aa79e12014-09-29 10:46:14 -04002467void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002468{
2469 int baseWidth = getBaseLevelWidth();
2470 int baseHeight = getBaseLevelHeight();
2471 int baseDepth = getBaseLevelDepth();
2472 GLenum baseFormat = getBaseLevelInternalFormat();
2473
2474 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2475 int levelCount = mipLevels();
2476 for (int level = 1; level < levelCount; level++)
2477 {
2478 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2479 }
Brandon Jones142ec422014-07-16 10:31:30 -07002480}
2481
Jamie Madillac7579c2014-09-17 16:59:33 -04002482unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002483{
Geoff Langef7b0162014-09-04 13:29:23 -04002484 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002485}
2486
Geoff Lang64f23f62014-09-10 14:40:12 -04002487gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002488{
2489 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002490 gl::Error error = ensureRenderTarget();
2491 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002492 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002493 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002494 }
2495
Geoff Langef7b0162014-09-04 13:29:23 -04002496 error = updateStorageLevel(index.mipIndex);
2497 if (error.isError())
2498 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002499 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002500 }
2501
Geoff Lang64f23f62014-09-10 14:40:12 -04002502 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002503}
2504
Geoff Langef7b0162014-09-04 13:29:23 -04002505gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002506{
2507 // Only initialize the first time this texture is used as a render target or shader resource
2508 if (mTexStorage)
2509 {
Geoff Langef7b0162014-09-04 13:29:23 -04002510 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002511 }
2512
2513 // do not attempt to create storage for nonexistant data
2514 if (!isLevelComplete(0))
2515 {
Geoff Langef7b0162014-09-04 13:29:23 -04002516 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002517 }
2518
2519 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2520
Geoff Langef7b0162014-09-04 13:29:23 -04002521 TextureStorage *storage = NULL;
2522 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2523 if (error.isError())
2524 {
2525 return error;
2526 }
2527
2528 error = setCompleteTexStorage(storage);
2529 if (error.isError())
2530 {
2531 SafeDelete(storage);
2532 return error;
2533 }
2534
Brandon Jones142ec422014-07-16 10:31:30 -07002535 ASSERT(mTexStorage);
2536
2537 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002538 error = updateStorage();
2539 if (error.isError())
2540 {
2541 return error;
2542 }
2543
2544 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002545}
2546
Geoff Langef7b0162014-09-04 13:29:23 -04002547gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002548{
2549 GLsizei width = getBaseLevelWidth();
2550 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002551 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002552 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002553
2554 ASSERT(width > 0 && height > 0 && depth > 0);
2555
2556 // use existing storage level count, when previously specified by TexStorage*D
2557 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2558
Geoff Langef7b0162014-09-04 13:29:23 -04002559 // TODO(geofflang): Verify storage creation succeeds
2560 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2561
2562 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002563}
2564
Geoff Langef7b0162014-09-04 13:29:23 -04002565gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002566{
2567 SafeDelete(mTexStorage);
2568 mTexStorage = newCompleteTexStorage;
2569 mDirtyImages = true;
2570
2571 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2572 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002573
2574 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002575}
2576
Geoff Langef7b0162014-09-04 13:29:23 -04002577gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002578{
2579 ASSERT(mTexStorage != NULL);
2580 GLint storageLevels = mTexStorage->getLevelCount();
2581 for (int level = 0; level < storageLevels; level++)
2582 {
2583 if (isLevelComplete(level))
2584 {
Geoff Langef7b0162014-09-04 13:29:23 -04002585 gl::Error error = updateStorageLevel(level);
2586 if (error.isError())
2587 {
2588 return error;
2589 }
Brandon Jones142ec422014-07-16 10:31:30 -07002590 }
2591 }
Geoff Langef7b0162014-09-04 13:29:23 -04002592
2593 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002594}
2595
Brandon Jones142ec422014-07-16 10:31:30 -07002596bool TextureD3D_2DArray::isValidLevel(int level) const
2597{
2598 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2599}
2600
2601bool TextureD3D_2DArray::isLevelComplete(int level) const
2602{
2603 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2604
2605 if (isImmutable())
2606 {
2607 return true;
2608 }
2609
2610 GLsizei width = getBaseLevelWidth();
2611 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002612 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002613
2614 if (width <= 0 || height <= 0 || layers <= 0)
2615 {
2616 return false;
2617 }
2618
2619 if (level == 0)
2620 {
2621 return true;
2622 }
2623
2624 if (getInternalFormat(level) != getInternalFormat(0))
2625 {
2626 return false;
2627 }
2628
2629 if (getWidth(level) != std::max(1, width >> level))
2630 {
2631 return false;
2632 }
2633
2634 if (getHeight(level) != std::max(1, height >> level))
2635 {
2636 return false;
2637 }
2638
Jamie Madill3269bcb2014-09-30 16:33:52 -04002639 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002640 {
2641 return false;
2642 }
2643
2644 return true;
2645}
2646
Geoff Langef7b0162014-09-04 13:29:23 -04002647gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002648{
2649 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2650 ASSERT(isLevelComplete(level));
2651
2652 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2653 {
2654 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2655 if (mImageArray[level][layer]->isDirty())
2656 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002657 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2658 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002659 gl::Error error = commitRegion(index, region);
2660 if (error.isError())
2661 {
2662 return error;
2663 }
Brandon Jones142ec422014-07-16 10:31:30 -07002664 }
2665 }
Geoff Langef7b0162014-09-04 13:29:23 -04002666
2667 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002668}
2669
2670void TextureD3D_2DArray::deleteImages()
2671{
2672 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2673 {
2674 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2675 {
2676 delete mImageArray[level][layer];
2677 }
2678 delete[] mImageArray[level];
2679 mImageArray[level] = NULL;
2680 mLayerCounts[level] = 0;
2681 }
2682}
2683
2684void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2685{
2686 // If there currently is a corresponding storage texture image, it has these parameters
2687 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2688 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002689 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002690 const GLenum storageFormat = getBaseLevelInternalFormat();
2691
2692 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2693 {
2694 delete mImageArray[level][layer];
2695 }
2696 delete[] mImageArray[level];
2697 mImageArray[level] = NULL;
2698 mLayerCounts[level] = depth;
2699
2700 if (depth > 0)
2701 {
2702 mImageArray[level] = new ImageD3D*[depth]();
2703
2704 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2705 {
2706 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2707 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2708 }
2709 }
2710
2711 if (mTexStorage)
2712 {
2713 const int storageLevels = mTexStorage->getLevelCount();
2714
2715 if ((level >= storageLevels && storageLevels != 0) ||
2716 width != storageWidth ||
2717 height != storageHeight ||
2718 depth != storageDepth ||
2719 internalformat != storageFormat) // Discard mismatched storage
2720 {
2721 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2722 {
2723 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2724 {
2725 mImageArray[level][layer]->markDirty();
2726 }
2727 }
2728
2729 delete mTexStorage;
2730 mTexStorage = NULL;
2731 mDirtyImages = true;
2732 }
2733 }
2734}
2735
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002736gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002737{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002738 ASSERT(index.hasLayer());
2739 GLint level = index.mipIndex;
2740 GLint layerTarget = index.layerIndex;
2741
Jamie Madill3269bcb2014-09-30 16:33:52 -04002742 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002743 {
2744 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill433bfd32014-10-20 12:07:36 -04002745 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002746 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002747 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002748 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002749 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002750
2751 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002752 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002753
2754 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002755}
2756
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002757gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2758{
2759 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2760}
2761
Jamie Madillcb83dc12014-09-29 10:46:12 -04002762gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2763{
2764 return gl::ImageIndex::Make2DArray(mip, layer);
2765}
2766
Brandon Jones78b1acd2014-07-15 15:33:07 -07002767}