blob: b4fd5a7a1fb0a6c718ab9ba4fce28a4d04b117d1 [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
Jamie Madillac7579c2014-09-17 16:59:33 -0400531 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700532 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
533
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400534 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400536 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
537 if (error.isError())
538 {
539 return error;
540 }
541
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700542 // Ensure we don't overwrite our newly initialized data
543 mImageArray[level]->markClean();
544
545 fastUnpacked = true;
546 }
547 }
548
549 if (!fastUnpacked)
550 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400551 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400552 if (error.isError())
553 {
554 return error;
555 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700556 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400557
558 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700559}
560
Geoff Langb5348332014-09-02 13:16:34 -0400561gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
562 GLsizei width, GLsizei height, GLsizei depth,
563 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700564{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700565 ASSERT(target == GL_TEXTURE_2D && depth == 1);
566
567 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
568 redefineImage(level, format, width, height);
569
Geoff Langb5348332014-09-02 13:16:34 -0400570 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700571}
572
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400573gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
574 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
575 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700576{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700577 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
578
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579 bool fastUnpacked = false;
580
Jamie Madillac7579c2014-09-17 16:59:33 -0400581 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400582 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
584 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400585 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400587 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700588 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400589 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
590 if (error.isError())
591 {
592 return error;
593 }
594
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700595 // Ensure we don't overwrite our newly initialized data
596 mImageArray[level]->markClean();
597
598 fastUnpacked = true;
599 }
600 }
601
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400602 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700603 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400604 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
605 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400607
608 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700609}
610
Geoff Langb5348332014-09-02 13:16:34 -0400611gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
612 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
613 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700615 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
616
Geoff Langb5348332014-09-02 13:16:34 -0400617 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
618 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 {
Geoff Langb5348332014-09-02 13:16:34 -0400620 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700621 }
Geoff Langb5348332014-09-02 13:16:34 -0400622
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400623 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
624 gl::Box region(xoffset, yoffset, 0, width, height, 1);
625 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626}
627
Geoff Langef7b0162014-09-04 13:29:23 -0400628gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
629 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700631 ASSERT(target == GL_TEXTURE_2D);
632
633 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
634 redefineImage(level, sizedInternalFormat, width, height);
635
Jamie Madill82bf0c52014-10-03 11:50:53 -0400636 gl::Rectangle sourceRect(x, y, width, height);
637
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638 if (!mImageArray[level]->isRenderableFormat())
639 {
Geoff Langef7b0162014-09-04 13:29:23 -0400640 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
641 if (error.isError())
642 {
643 return error;
644 }
645
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700646 mDirtyImages = true;
647 }
648 else
649 {
Geoff Langef7b0162014-09-04 13:29:23 -0400650 gl::Error error = ensureRenderTarget();
651 if (error.isError())
652 {
653 return error;
654 }
655
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656 mImageArray[level]->markClean();
657
658 if (width != 0 && height != 0 && isValidLevel(level))
659 {
Geoff Langef7b0162014-09-04 13:29:23 -0400660 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
661 if (error.isError())
662 {
663 return error;
664 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665 }
666 }
Geoff Langef7b0162014-09-04 13:29:23 -0400667
668 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669}
670
Geoff Langef7b0162014-09-04 13:29:23 -0400671gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
672 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700673{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700674 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
675
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700676 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
677 // the current level we're copying to is defined (with appropriate format, width & height)
678 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
679
Jamie Madill82bf0c52014-10-03 11:50:53 -0400680 gl::Rectangle sourceRect(x, y, width, height);
681
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700682 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
683 {
Geoff Langef7b0162014-09-04 13:29:23 -0400684 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
685 if (error.isError())
686 {
687 return error;
688 }
689
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700690 mDirtyImages = true;
691 }
692 else
693 {
Geoff Langef7b0162014-09-04 13:29:23 -0400694 gl::Error error = ensureRenderTarget();
695 if (error.isError())
696 {
697 return error;
698 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700699
700 if (isValidLevel(level))
701 {
Geoff Langef7b0162014-09-04 13:29:23 -0400702 error = updateStorageLevel(level);
703 if (error.isError())
704 {
705 return error;
706 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700707
Geoff Langef7b0162014-09-04 13:29:23 -0400708 error = mRenderer->copyImage2D(source, sourceRect,
709 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
710 xoffset, yoffset, mTexStorage, level);
711 if (error.isError())
712 {
713 return error;
714 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700715 }
716 }
Geoff Langef7b0162014-09-04 13:29:23 -0400717
718 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700719}
720
Geoff Lang1f8532b2014-09-05 09:46:13 -0400721gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700722{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700723 ASSERT(target == GL_TEXTURE_2D && depth == 1);
724
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700725 for (int level = 0; level < levels; level++)
726 {
727 GLsizei levelWidth = std::max(1, width >> level);
728 GLsizei levelHeight = std::max(1, height >> level);
729 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
730 }
731
732 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
733 {
734 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
735 }
736
Geoff Lang1f8532b2014-09-05 09:46:13 -0400737 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400738 bool renderTarget = IsRenderTargetUsage(mUsage);
739 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400740
741 gl::Error error = setCompleteTexStorage(storage);
742 if (error.isError())
743 {
744 SafeDelete(storage);
745 return error;
746 }
747
748 mImmutable = true;
749
750 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700751}
752
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700753void TextureD3D_2D::bindTexImage(egl::Surface *surface)
754{
755 GLenum internalformat = surface->getFormat();
756
757 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
758
759 if (mTexStorage)
760 {
761 SafeDelete(mTexStorage);
762 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400763
764 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765
766 mDirtyImages = true;
767}
768
769void TextureD3D_2D::releaseTexImage()
770{
771 if (mTexStorage)
772 {
773 SafeDelete(mTexStorage);
774 }
775
776 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
777 {
778 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
779 }
780}
781
Jamie Madill4aa79e12014-09-29 10:46:14 -0400782void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700783{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700784 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700786 for (int level = 1; level < levelCount; level++)
787 {
788 redefineImage(level, getBaseLevelInternalFormat(),
789 std::max(getBaseLevelWidth() >> level, 1),
790 std::max(getBaseLevelHeight() >> level, 1));
791 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700792}
793
Jamie Madillac7579c2014-09-17 16:59:33 -0400794unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700795{
Jamie Madillac7579c2014-09-17 16:59:33 -0400796 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400797 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700798}
799
Jamie Madillac7579c2014-09-17 16:59:33 -0400800RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700801{
Jamie Madillac7579c2014-09-17 16:59:33 -0400802 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700803
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700804 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400805 gl::Error error = ensureRenderTarget();
806 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700807 {
808 return NULL;
809 }
810
Geoff Langef7b0162014-09-04 13:29:23 -0400811 error = updateStorageLevel(index.mipIndex);
812 if (error.isError())
813 {
814 return NULL;
815 }
816
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400817 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818}
819
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700820bool TextureD3D_2D::isValidLevel(int level) const
821{
822 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
823}
824
825bool TextureD3D_2D::isLevelComplete(int level) const
826{
827 if (isImmutable())
828 {
829 return true;
830 }
831
Brandon Jones78b1acd2014-07-15 15:33:07 -0700832 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700833
834 GLsizei width = baseImage->getWidth();
835 GLsizei height = baseImage->getHeight();
836
837 if (width <= 0 || height <= 0)
838 {
839 return false;
840 }
841
842 // The base image level is complete if the width and height are positive
843 if (level == 0)
844 {
845 return true;
846 }
847
848 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700849 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700850
851 if (image->getInternalFormat() != baseImage->getInternalFormat())
852 {
853 return false;
854 }
855
856 if (image->getWidth() != std::max(1, width >> level))
857 {
858 return false;
859 }
860
861 if (image->getHeight() != std::max(1, height >> level))
862 {
863 return false;
864 }
865
866 return true;
867}
868
869// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400870gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700871{
872 // Only initialize the first time this texture is used as a render target or shader resource
873 if (mTexStorage)
874 {
Geoff Langef7b0162014-09-04 13:29:23 -0400875 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700876 }
877
878 // do not attempt to create storage for nonexistant data
879 if (!isLevelComplete(0))
880 {
Geoff Langef7b0162014-09-04 13:29:23 -0400881 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882 }
883
884 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
885
Geoff Langef7b0162014-09-04 13:29:23 -0400886 TextureStorage *storage = NULL;
887 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
888 if (error.isError())
889 {
890 return error;
891 }
892
893 error = setCompleteTexStorage(storage);
894 if (error.isError())
895 {
896 SafeDelete(storage);
897 return error;
898 }
899
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700900 ASSERT(mTexStorage);
901
902 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400903 error = updateStorage();
904 if (error.isError())
905 {
906 return error;
907 }
908
909 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700910}
911
Geoff Langef7b0162014-09-04 13:29:23 -0400912gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700913{
914 GLsizei width = getBaseLevelWidth();
915 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400916 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700917
918 ASSERT(width > 0 && height > 0);
919
920 // use existing storage level count, when previously specified by TexStorage*D
921 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
922
Geoff Langef7b0162014-09-04 13:29:23 -0400923 // TODO(geofflang): Determine if the texture creation succeeded
924 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
925
926 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700927}
928
Geoff Langef7b0162014-09-04 13:29:23 -0400929gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700930{
Geoff Langef7b0162014-09-04 13:29:23 -0400931 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700932 {
Geoff Langef7b0162014-09-04 13:29:23 -0400933 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700934 {
Geoff Langef7b0162014-09-04 13:29:23 -0400935 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
936 if (error.isError())
937 {
938 return error;
939 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700940 }
941 }
942
Geoff Langef7b0162014-09-04 13:29:23 -0400943 SafeDelete(mTexStorage);
944 mTexStorage = newCompleteTexStorage;
945
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700946 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400947
948 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700949}
950
Geoff Langef7b0162014-09-04 13:29:23 -0400951gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700952{
953 ASSERT(mTexStorage != NULL);
954 GLint storageLevels = mTexStorage->getLevelCount();
955 for (int level = 0; level < storageLevels; level++)
956 {
957 if (mImageArray[level]->isDirty() && isLevelComplete(level))
958 {
Geoff Langef7b0162014-09-04 13:29:23 -0400959 gl::Error error = updateStorageLevel(level);
960 if (error.isError())
961 {
962 return error;
963 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700964 }
965 }
Geoff Langef7b0162014-09-04 13:29:23 -0400966
967 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700968}
969
Geoff Langef7b0162014-09-04 13:29:23 -0400970gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700971{
972 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
973 ASSERT(isLevelComplete(level));
974
975 if (mImageArray[level]->isDirty())
976 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400977 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
978 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -0400979 gl::Error error = commitRegion(index, region);
980 if (error.isError())
981 {
982 return error;
983 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700984 }
Geoff Langef7b0162014-09-04 13:29:23 -0400985
986 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700987}
988
989void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
990{
991 // If there currently is a corresponding storage texture image, it has these parameters
992 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
993 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
994 const GLenum storageFormat = getBaseLevelInternalFormat();
995
996 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
997
998 if (mTexStorage)
999 {
1000 const int storageLevels = mTexStorage->getLevelCount();
1001
1002 if ((level >= storageLevels && storageLevels != 0) ||
1003 width != storageWidth ||
1004 height != storageHeight ||
1005 internalformat != storageFormat) // Discard mismatched storage
1006 {
1007 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1008 {
1009 mImageArray[i]->markDirty();
1010 }
1011
1012 SafeDelete(mTexStorage);
1013 mDirtyImages = true;
1014 }
1015 }
1016}
1017
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001018gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001019{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001020 ASSERT(!index.hasLayer());
1021 GLint level = index.mipIndex;
1022
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001023 if (isValidLevel(level))
1024 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001025 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001026 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001027 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001028 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001029 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001030 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001031
1032 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001033 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001034
1035 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001036}
1037
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001038gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1039{
1040 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1041}
Brandon Jones0511e802014-07-14 16:27:26 -07001042
Jamie Madillcb83dc12014-09-29 10:46:12 -04001043gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1044{
1045 // "layer" does not apply to 2D Textures.
1046 return gl::ImageIndex::Make2D(mip);
1047}
1048
Brandon Jones78b1acd2014-07-15 15:33:07 -07001049TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001050 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001051{
1052 for (int i = 0; i < 6; i++)
1053 {
1054 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1055 {
1056 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1057 }
1058 }
1059}
1060
1061TextureD3D_Cube::~TextureD3D_Cube()
1062{
Austin Kinross69822602014-08-12 15:51:37 -07001063 // Delete the Images before the TextureStorage.
1064 // Images might be relying on the TextureStorage for some of their data.
1065 // 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 -07001066 for (int i = 0; i < 6; i++)
1067 {
1068 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1069 {
1070 SafeDelete(mImageArray[i][j]);
1071 }
1072 }
Austin Kinross69822602014-08-12 15:51:37 -07001073
1074 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001075}
1076
Brandon Jonescef06ff2014-08-05 13:27:48 -07001077Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001078{
1079 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001080 ASSERT(layer < 6);
1081 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001082}
1083
Jamie Madillfeda4d22014-09-17 13:03:29 -04001084Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1085{
1086 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1087 ASSERT(index.layerIndex < 6);
1088 return mImageArray[index.layerIndex][index.mipIndex];
1089}
1090
Brandon Jonescef06ff2014-08-05 13:27:48 -07001091GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001092{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001093 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1094 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001095}
1096
Brandon Jonescef06ff2014-08-05 13:27:48 -07001097GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001098{
1099 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001100 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001101 else
1102 return GL_NONE;
1103}
1104
Brandon Jonescef06ff2014-08-05 13:27:48 -07001105bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001106{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001107 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001108}
1109
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001110gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1111 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1112 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001113{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001114 ASSERT(depth == 1);
1115
Geoff Lang5d601382014-07-22 15:14:06 -04001116 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001117 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001118
Jamie Madillba6bc952014-10-06 10:56:22 -04001119 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001120
Jamie Madillba6bc952014-10-06 10:56:22 -04001121 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001122}
1123
Geoff Langb5348332014-09-02 13:16:34 -04001124gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1125 GLsizei width, GLsizei height, GLsizei depth,
1126 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001127{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001128 ASSERT(depth == 1);
1129
Brandon Jones0511e802014-07-14 16:27:26 -07001130 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001131 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1132
Brandon Jones0511e802014-07-14 16:27:26 -07001133 redefineImage(faceIndex, level, format, width, height);
1134
Geoff Langb5348332014-09-02 13:16:34 -04001135 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001136}
1137
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001138gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1139 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1140 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001141{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001142 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001143 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001144 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001145}
1146
Geoff Langb5348332014-09-02 13:16:34 -04001147gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1148 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1149 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001150{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001151 ASSERT(depth == 1 && zoffset == 0);
1152
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001153 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001154
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001155 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 -04001156 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001157 {
Geoff Langb5348332014-09-02 13:16:34 -04001158 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001159 }
Geoff Langb5348332014-09-02 13:16:34 -04001160
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001161 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1162 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001163}
1164
Geoff Langef7b0162014-09-04 13:29:23 -04001165gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1166 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001167{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001168 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001169 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1170
Brandon Jones0511e802014-07-14 16:27:26 -07001171 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1172
Jamie Madill82bf0c52014-10-03 11:50:53 -04001173 gl::Rectangle sourceRect(x, y, width, height);
1174
Brandon Jones0511e802014-07-14 16:27:26 -07001175 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1176 {
Geoff Langef7b0162014-09-04 13:29:23 -04001177 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1178 if (error.isError())
1179 {
1180 return error;
1181 }
1182
Brandon Jones0511e802014-07-14 16:27:26 -07001183 mDirtyImages = true;
1184 }
1185 else
1186 {
Geoff Langef7b0162014-09-04 13:29:23 -04001187 gl::Error error = ensureRenderTarget();
1188 if (error.isError())
1189 {
1190 return error;
1191 }
1192
Brandon Jones0511e802014-07-14 16:27:26 -07001193 mImageArray[faceIndex][level]->markClean();
1194
1195 ASSERT(width == height);
1196
1197 if (width > 0 && isValidFaceLevel(faceIndex, level))
1198 {
Geoff Langef7b0162014-09-04 13:29:23 -04001199 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1200 if (error.isError())
1201 {
1202 return error;
1203 }
Brandon Jones0511e802014-07-14 16:27:26 -07001204 }
1205 }
Geoff Langef7b0162014-09-04 13:29:23 -04001206
1207 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001208}
1209
Geoff Langef7b0162014-09-04 13:29:23 -04001210gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1211 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001212{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001213 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001214
1215 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1216 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1217 // rely on the "getBaseLevel*" methods reliably otherwise.
1218 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1219
Jamie Madill82bf0c52014-10-03 11:50:53 -04001220 gl::Rectangle sourceRect(x, y, width, height);
1221
Brandon Jones0511e802014-07-14 16:27:26 -07001222 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1223 {
Geoff Langef7b0162014-09-04 13:29:23 -04001224 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1225 if (error.isError())
1226 {
1227 return error;
1228 }
1229
Brandon Jones0511e802014-07-14 16:27:26 -07001230 mDirtyImages = true;
1231 }
1232 else
1233 {
Geoff Langef7b0162014-09-04 13:29:23 -04001234 gl::Error error = ensureRenderTarget();
1235 if (error.isError())
1236 {
1237 return error;
1238 }
Brandon Jones0511e802014-07-14 16:27:26 -07001239
1240 if (isValidFaceLevel(faceIndex, level))
1241 {
Geoff Langef7b0162014-09-04 13:29:23 -04001242 error = updateStorageFaceLevel(faceIndex, level);
1243 if (error.isError())
1244 {
1245 return error;
1246 }
Brandon Jones0511e802014-07-14 16:27:26 -07001247
Geoff Langef7b0162014-09-04 13:29:23 -04001248 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1249 xoffset, yoffset, mTexStorage, target, level);
1250 if (error.isError())
1251 {
1252 return error;
1253 }
Brandon Jones0511e802014-07-14 16:27:26 -07001254 }
1255 }
Geoff Langef7b0162014-09-04 13:29:23 -04001256
1257 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001258}
1259
Geoff Lang1f8532b2014-09-05 09:46:13 -04001260gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001261{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001262 ASSERT(width == height);
1263 ASSERT(depth == 1);
1264
Brandon Jones0511e802014-07-14 16:27:26 -07001265 for (int level = 0; level < levels; level++)
1266 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001267 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001268 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1269 {
1270 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1271 }
1272 }
1273
1274 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1275 {
1276 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1277 {
1278 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1279 }
1280 }
1281
Geoff Lang1f8532b2014-09-05 09:46:13 -04001282 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001283 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001284 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001285
1286 gl::Error error = setCompleteTexStorage(storage);
1287 if (error.isError())
1288 {
1289 SafeDelete(storage);
1290 return error;
1291 }
1292
1293 mImmutable = true;
1294
1295 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001296}
1297
Brandon Jones0511e802014-07-14 16:27:26 -07001298// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1299bool TextureD3D_Cube::isCubeComplete() const
1300{
1301 int baseWidth = getBaseLevelWidth();
1302 int baseHeight = getBaseLevelHeight();
1303 GLenum baseFormat = getBaseLevelInternalFormat();
1304
1305 if (baseWidth <= 0 || baseWidth != baseHeight)
1306 {
1307 return false;
1308 }
1309
1310 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1311 {
1312 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1313
1314 if (faceBaseImage.getWidth() != baseWidth ||
1315 faceBaseImage.getHeight() != baseHeight ||
1316 faceBaseImage.getInternalFormat() != baseFormat )
1317 {
1318 return false;
1319 }
1320 }
1321
1322 return true;
1323}
1324
Brandon Jones6053a522014-07-25 16:22:09 -07001325void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1326{
1327 UNREACHABLE();
1328}
1329
1330void TextureD3D_Cube::releaseTexImage()
1331{
1332 UNREACHABLE();
1333}
1334
1335
Jamie Madill4aa79e12014-09-29 10:46:14 -04001336void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001337{
1338 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1339 int levelCount = mipLevels();
1340 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1341 {
1342 for (int level = 1; level < levelCount; level++)
1343 {
1344 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1345 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1346 }
1347 }
Brandon Jones0511e802014-07-14 16:27:26 -07001348}
1349
Jamie Madillac7579c2014-09-17 16:59:33 -04001350unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001351{
Geoff Langef7b0162014-09-04 13:29:23 -04001352 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001353}
1354
Jamie Madillac7579c2014-09-17 16:59:33 -04001355RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001356{
Jamie Madillac7579c2014-09-17 16:59:33 -04001357 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001358
1359 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001360 gl::Error error = ensureRenderTarget();
1361 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001362 {
1363 return NULL;
1364 }
1365
Geoff Langef7b0162014-09-04 13:29:23 -04001366 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1367 if (error.isError())
1368 {
1369 return NULL;
1370 }
1371
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001372 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001373}
1374
Geoff Langef7b0162014-09-04 13:29:23 -04001375gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001376{
1377 // Only initialize the first time this texture is used as a render target or shader resource
1378 if (mTexStorage)
1379 {
Geoff Langef7b0162014-09-04 13:29:23 -04001380 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001381 }
1382
1383 // do not attempt to create storage for nonexistant data
1384 if (!isFaceLevelComplete(0, 0))
1385 {
Geoff Langef7b0162014-09-04 13:29:23 -04001386 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001387 }
1388
1389 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1390
Geoff Langef7b0162014-09-04 13:29:23 -04001391 TextureStorage *storage = NULL;
1392 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1393 if (error.isError())
1394 {
1395 return error;
1396 }
1397
1398 error = setCompleteTexStorage(storage);
1399 if (error.isError())
1400 {
1401 SafeDelete(storage);
1402 return error;
1403 }
1404
Brandon Jones0511e802014-07-14 16:27:26 -07001405 ASSERT(mTexStorage);
1406
1407 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001408 error = updateStorage();
1409 if (error.isError())
1410 {
1411 return error;
1412 }
1413
1414 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001415}
1416
Geoff Langef7b0162014-09-04 13:29:23 -04001417gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001418{
1419 GLsizei size = getBaseLevelWidth();
1420
1421 ASSERT(size > 0);
1422
1423 // use existing storage level count, when previously specified by TexStorage*D
1424 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1425
Geoff Langef7b0162014-09-04 13:29:23 -04001426 // TODO (geofflang): detect if storage creation succeeded
1427 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1428
1429 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001430}
1431
Geoff Langef7b0162014-09-04 13:29:23 -04001432gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001433{
Geoff Langef7b0162014-09-04 13:29:23 -04001434 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001435 {
1436 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1437 {
Geoff Langef7b0162014-09-04 13:29:23 -04001438 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001439 {
Geoff Langef7b0162014-09-04 13:29:23 -04001440 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1441 if (error.isError())
1442 {
1443 return error;
1444 }
Brandon Jones0511e802014-07-14 16:27:26 -07001445 }
1446 }
1447 }
1448
Geoff Langef7b0162014-09-04 13:29:23 -04001449 SafeDelete(mTexStorage);
1450 mTexStorage = newCompleteTexStorage;
1451
Brandon Jones0511e802014-07-14 16:27:26 -07001452 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001453 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001454}
1455
Geoff Langef7b0162014-09-04 13:29:23 -04001456gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001457{
1458 ASSERT(mTexStorage != NULL);
1459 GLint storageLevels = mTexStorage->getLevelCount();
1460 for (int face = 0; face < 6; face++)
1461 {
1462 for (int level = 0; level < storageLevels; level++)
1463 {
1464 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1465 {
Geoff Langef7b0162014-09-04 13:29:23 -04001466 gl::Error error = updateStorageFaceLevel(face, level);
1467 if (error.isError())
1468 {
1469 return error;
1470 }
Brandon Jones0511e802014-07-14 16:27:26 -07001471 }
1472 }
1473 }
Geoff Langef7b0162014-09-04 13:29:23 -04001474
1475 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001476}
1477
Brandon Jones0511e802014-07-14 16:27:26 -07001478bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1479{
1480 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1481}
1482
Brandon Jones0511e802014-07-14 16:27:26 -07001483bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1484{
1485 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1486
1487 if (isImmutable())
1488 {
1489 return true;
1490 }
1491
1492 int baseSize = getBaseLevelWidth();
1493
1494 if (baseSize <= 0)
1495 {
1496 return false;
1497 }
1498
1499 // "isCubeComplete" checks for base level completeness and we must call that
1500 // to determine if any face at level 0 is complete. We omit that check here
1501 // to avoid re-checking cube-completeness for every face at level 0.
1502 if (level == 0)
1503 {
1504 return true;
1505 }
1506
1507 // Check that non-zero levels are consistent with the base level.
1508 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1509
1510 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1511 {
1512 return false;
1513 }
1514
1515 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1516 {
1517 return false;
1518 }
1519
1520 return true;
1521}
1522
Geoff Langef7b0162014-09-04 13:29:23 -04001523gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001524{
1525 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1526 ImageD3D *image = mImageArray[faceIndex][level];
1527
1528 if (image->isDirty())
1529 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001530 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1531 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1532 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001533 gl::Error error = commitRegion(index, region);
1534 if (error.isError())
1535 {
1536 return error;
1537 }
Brandon Jones0511e802014-07-14 16:27:26 -07001538 }
Geoff Langef7b0162014-09-04 13:29:23 -04001539
1540 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001541}
1542
1543void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1544{
1545 // If there currently is a corresponding storage texture image, it has these parameters
1546 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1547 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1548 const GLenum storageFormat = getBaseLevelInternalFormat();
1549
1550 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1551
1552 if (mTexStorage)
1553 {
1554 const int storageLevels = mTexStorage->getLevelCount();
1555
1556 if ((level >= storageLevels && storageLevels != 0) ||
1557 width != storageWidth ||
1558 height != storageHeight ||
1559 internalformat != storageFormat) // Discard mismatched storage
1560 {
1561 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1562 {
1563 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1564 {
1565 mImageArray[faceIndex][level]->markDirty();
1566 }
1567 }
1568
1569 SafeDelete(mTexStorage);
1570
1571 mDirtyImages = true;
1572 }
1573 }
1574}
1575
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001576gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001577{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001578 ASSERT(index.hasLayer());
1579
1580 GLint level = index.mipIndex;
1581 int faceIndex = static_cast<int>(index.layerIndex);
1582
Brandon Jones0511e802014-07-14 16:27:26 -07001583 if (isValidFaceLevel(faceIndex, level))
1584 {
1585 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001586 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001587 if (error.isError())
1588 {
1589 return error;
1590 }
1591
1592 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001593 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001594
1595 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001596}
1597
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001598gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1599{
1600 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1601}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001602
Jamie Madillcb83dc12014-09-29 10:46:12 -04001603gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1604{
1605 // The "layer" of the image index corresponds to the cube face
1606 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1607}
1608
Brandon Jones78b1acd2014-07-15 15:33:07 -07001609TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001610 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001611{
1612 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1613 {
1614 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1615 }
1616}
1617
1618TextureD3D_3D::~TextureD3D_3D()
1619{
Austin Kinross69822602014-08-12 15:51:37 -07001620 // Delete the Images before the TextureStorage.
1621 // Images might be relying on the TextureStorage for some of their data.
1622 // 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 -07001623 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1624 {
1625 delete mImageArray[i];
1626 }
Austin Kinross69822602014-08-12 15:51:37 -07001627
1628 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001629}
1630
Brandon Jonescef06ff2014-08-05 13:27:48 -07001631Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001632{
1633 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001634 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001635 return mImageArray[level];
1636}
1637
Jamie Madillfeda4d22014-09-17 13:03:29 -04001638Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1639{
1640 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001641 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001642 ASSERT(index.type == GL_TEXTURE_3D);
1643 return mImageArray[index.mipIndex];
1644}
1645
Brandon Jonescef06ff2014-08-05 13:27:48 -07001646GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001647{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001648 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1649 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001650}
1651
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652GLsizei TextureD3D_3D::getWidth(GLint level) const
1653{
1654 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1655 return mImageArray[level]->getWidth();
1656 else
1657 return 0;
1658}
1659
1660GLsizei TextureD3D_3D::getHeight(GLint level) const
1661{
1662 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1663 return mImageArray[level]->getHeight();
1664 else
1665 return 0;
1666}
1667
1668GLsizei TextureD3D_3D::getDepth(GLint level) const
1669{
1670 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1671 return mImageArray[level]->getDepth();
1672 else
1673 return 0;
1674}
1675
1676GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1677{
1678 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1679 return mImageArray[level]->getInternalFormat();
1680 else
1681 return GL_NONE;
1682}
1683
1684bool TextureD3D_3D::isDepth(GLint level) const
1685{
Geoff Lang5d601382014-07-22 15:14:06 -04001686 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001687}
1688
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001689gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1690 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1691 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001692{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001693 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001694 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1695
Brandon Jones78b1acd2014-07-15 15:33:07 -07001696 redefineImage(level, sizedInternalFormat, width, height, depth);
1697
1698 bool fastUnpacked = false;
1699
Jamie Madillba6bc952014-10-06 10:56:22 -04001700 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1701
Brandon Jones78b1acd2014-07-15 15:33:07 -07001702 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1703 if (isFastUnpackable(unpack, sizedInternalFormat))
1704 {
1705 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001706 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001707 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1708
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001709 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001710 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001711 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1712 if (error.isError())
1713 {
1714 return error;
1715 }
1716
Brandon Jones78b1acd2014-07-15 15:33:07 -07001717 // Ensure we don't overwrite our newly initialized data
1718 mImageArray[level]->markClean();
1719
1720 fastUnpacked = true;
1721 }
1722 }
1723
1724 if (!fastUnpacked)
1725 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001726 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001727 if (error.isError())
1728 {
1729 return error;
1730 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001731 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001732
1733 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001734}
1735
Geoff Langb5348332014-09-02 13:16:34 -04001736gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1737 GLsizei width, GLsizei height,GLsizei depth,
1738 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001740 ASSERT(target == GL_TEXTURE_3D);
1741
Brandon Jones78b1acd2014-07-15 15:33:07 -07001742 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1743 redefineImage(level, format, width, height, depth);
1744
Geoff Langb5348332014-09-02 13:16:34 -04001745 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001746}
1747
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001748gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1749 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1750 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001751{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001752 ASSERT(target == GL_TEXTURE_3D);
1753
Brandon Jones78b1acd2014-07-15 15:33:07 -07001754 bool fastUnpacked = false;
1755
Jamie Madillac7579c2014-09-17 16:59:33 -04001756 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1757
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1759 if (isFastUnpackable(unpack, getInternalFormat(level)))
1760 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001761 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001763 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001764 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001765 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001766 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1767 if (error.isError())
1768 {
1769 return error;
1770 }
1771
Brandon Jones78b1acd2014-07-15 15:33:07 -07001772 // Ensure we don't overwrite our newly initialized data
1773 mImageArray[level]->markClean();
1774
1775 fastUnpacked = true;
1776 }
1777 }
1778
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001779 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001780 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001781 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1782 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001783 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001784
1785 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001786}
1787
Geoff Langb5348332014-09-02 13:16:34 -04001788gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1789 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1790 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001792 ASSERT(target == GL_TEXTURE_3D);
1793
Geoff Langb5348332014-09-02 13:16:34 -04001794 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1795 format, imageSize, pixels, mImageArray[level]);
1796 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001797 {
Geoff Langb5348332014-09-02 13:16:34 -04001798 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001799 }
Geoff Langb5348332014-09-02 13:16:34 -04001800
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001801 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1802 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1803 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001804}
1805
Geoff Langef7b0162014-09-04 13:29:23 -04001806gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1807 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001808{
1809 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001810 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001811}
1812
Geoff Langef7b0162014-09-04 13:29:23 -04001813gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1814 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001816 ASSERT(target == GL_TEXTURE_3D);
1817
Brandon Jones78b1acd2014-07-15 15:33:07 -07001818 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1819 // the current level we're copying to is defined (with appropriate format, width & height)
1820 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1821
Jamie Madill82bf0c52014-10-03 11:50:53 -04001822 gl::Rectangle sourceRect(x, y, width, height);
1823
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1825 {
Geoff Langef7b0162014-09-04 13:29:23 -04001826 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1827 if (error.isError())
1828 {
1829 return error;
1830 }
1831
Brandon Jones78b1acd2014-07-15 15:33:07 -07001832 mDirtyImages = true;
1833 }
1834 else
1835 {
Geoff Langef7b0162014-09-04 13:29:23 -04001836 gl::Error error = ensureRenderTarget();
1837 if (error.isError())
1838 {
1839 return error;
1840 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001841
1842 if (isValidLevel(level))
1843 {
Geoff Langef7b0162014-09-04 13:29:23 -04001844 error = updateStorageLevel(level);
1845 if (error.isError())
1846 {
1847 return error;
1848 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849
Geoff Langef7b0162014-09-04 13:29:23 -04001850 error = mRenderer->copyImage3D(source, sourceRect,
1851 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1852 xoffset, yoffset, zoffset, mTexStorage, level);
1853 if (error.isError())
1854 {
1855 return error;
1856 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001857 }
1858 }
Geoff Langef7b0162014-09-04 13:29:23 -04001859
1860 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861}
1862
Geoff Lang1f8532b2014-09-05 09:46:13 -04001863gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001864{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001865 ASSERT(target == GL_TEXTURE_3D);
1866
Brandon Jones78b1acd2014-07-15 15:33:07 -07001867 for (int level = 0; level < levels; level++)
1868 {
1869 GLsizei levelWidth = std::max(1, width >> level);
1870 GLsizei levelHeight = std::max(1, height >> level);
1871 GLsizei levelDepth = std::max(1, depth >> level);
1872 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1873 }
1874
1875 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1876 {
1877 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1878 }
1879
Geoff Lang1f8532b2014-09-05 09:46:13 -04001880 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001881 bool renderTarget = IsRenderTargetUsage(mUsage);
1882 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001883
1884 gl::Error error = setCompleteTexStorage(storage);
1885 if (error.isError())
1886 {
1887 SafeDelete(storage);
1888 return error;
1889 }
1890
1891 mImmutable = true;
1892
1893 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001894}
1895
Brandon Jones6053a522014-07-25 16:22:09 -07001896void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001897{
Brandon Jones6053a522014-07-25 16:22:09 -07001898 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001899}
1900
Brandon Jones6053a522014-07-25 16:22:09 -07001901void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001902{
Brandon Jones6053a522014-07-25 16:22:09 -07001903 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001904}
1905
Brandon Jones6053a522014-07-25 16:22:09 -07001906
Jamie Madill4aa79e12014-09-29 10:46:14 -04001907void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001908{
1909 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1910 int levelCount = mipLevels();
1911 for (int level = 1; level < levelCount; level++)
1912 {
1913 redefineImage(level, getBaseLevelInternalFormat(),
1914 std::max(getBaseLevelWidth() >> level, 1),
1915 std::max(getBaseLevelHeight() >> level, 1),
1916 std::max(getBaseLevelDepth() >> level, 1));
1917 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001918}
1919
Jamie Madillac7579c2014-09-17 16:59:33 -04001920unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001921{
Geoff Langef7b0162014-09-04 13:29:23 -04001922 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001923}
1924
Jamie Madillac7579c2014-09-17 16:59:33 -04001925RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001926{
1927 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001928 gl::Error error = ensureRenderTarget();
1929 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001930 {
1931 return NULL;
1932 }
1933
Jamie Madillac7579c2014-09-17 16:59:33 -04001934 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001935 {
Geoff Langef7b0162014-09-04 13:29:23 -04001936 error = updateStorage();
1937 if (error.isError())
1938 {
1939 return NULL;
1940 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001941 }
1942 else
1943 {
Geoff Langef7b0162014-09-04 13:29:23 -04001944 error = updateStorageLevel(index.mipIndex);
1945 if (error.isError())
1946 {
1947 return NULL;
1948 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949 }
1950
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001951 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001952}
1953
Geoff Langef7b0162014-09-04 13:29:23 -04001954gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001955{
1956 // Only initialize the first time this texture is used as a render target or shader resource
1957 if (mTexStorage)
1958 {
Geoff Langef7b0162014-09-04 13:29:23 -04001959 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001960 }
1961
1962 // do not attempt to create storage for nonexistant data
1963 if (!isLevelComplete(0))
1964 {
Geoff Langef7b0162014-09-04 13:29:23 -04001965 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001966 }
1967
1968 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1969
Geoff Langef7b0162014-09-04 13:29:23 -04001970 rx::TextureStorage *storage = NULL;
1971 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1972 if (error.isError())
1973 {
1974 return error;
1975 }
1976
1977 error = setCompleteTexStorage(storage);
1978 if (error.isError())
1979 {
1980 SafeDelete(storage);
1981 return error;
1982 }
1983
Brandon Jones78b1acd2014-07-15 15:33:07 -07001984 ASSERT(mTexStorage);
1985
1986 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001987 error = updateStorage();
1988 if (error.isError())
1989 {
1990 return error;
1991 }
1992
1993 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001994}
1995
Geoff Langef7b0162014-09-04 13:29:23 -04001996gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001997{
1998 GLsizei width = getBaseLevelWidth();
1999 GLsizei height = getBaseLevelHeight();
2000 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002001 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002
2003 ASSERT(width > 0 && height > 0 && depth > 0);
2004
2005 // use existing storage level count, when previously specified by TexStorage*D
2006 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2007
Geoff Langef7b0162014-09-04 13:29:23 -04002008 // TODO: Verify creation of the storage succeeded
2009 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2010
2011 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002012}
2013
Geoff Langef7b0162014-09-04 13:29:23 -04002014gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002015{
2016 SafeDelete(mTexStorage);
2017 mTexStorage = newCompleteTexStorage;
2018 mDirtyImages = true;
2019
2020 // We do not support managed 3D storage, as that is D3D9/ES2-only
2021 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002022
2023 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002024}
2025
Geoff Langef7b0162014-09-04 13:29:23 -04002026gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002027{
2028 ASSERT(mTexStorage != NULL);
2029 GLint storageLevels = mTexStorage->getLevelCount();
2030 for (int level = 0; level < storageLevels; level++)
2031 {
2032 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2033 {
Geoff Langef7b0162014-09-04 13:29:23 -04002034 gl::Error error = updateStorageLevel(level);
2035 if (error.isError())
2036 {
2037 return error;
2038 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002039 }
2040 }
Geoff Langef7b0162014-09-04 13:29:23 -04002041
2042 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002043}
2044
Brandon Jones78b1acd2014-07-15 15:33:07 -07002045bool TextureD3D_3D::isValidLevel(int level) const
2046{
2047 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2048}
2049
2050bool TextureD3D_3D::isLevelComplete(int level) const
2051{
2052 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2053
2054 if (isImmutable())
2055 {
2056 return true;
2057 }
2058
2059 GLsizei width = getBaseLevelWidth();
2060 GLsizei height = getBaseLevelHeight();
2061 GLsizei depth = getBaseLevelDepth();
2062
2063 if (width <= 0 || height <= 0 || depth <= 0)
2064 {
2065 return false;
2066 }
2067
2068 if (level == 0)
2069 {
2070 return true;
2071 }
2072
2073 ImageD3D *levelImage = mImageArray[level];
2074
2075 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2076 {
2077 return false;
2078 }
2079
2080 if (levelImage->getWidth() != std::max(1, width >> level))
2081 {
2082 return false;
2083 }
2084
2085 if (levelImage->getHeight() != std::max(1, height >> level))
2086 {
2087 return false;
2088 }
2089
2090 if (levelImage->getDepth() != std::max(1, depth >> level))
2091 {
2092 return false;
2093 }
2094
2095 return true;
2096}
2097
Geoff Langef7b0162014-09-04 13:29:23 -04002098gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099{
2100 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2101 ASSERT(isLevelComplete(level));
2102
2103 if (mImageArray[level]->isDirty())
2104 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002105 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2106 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002107 gl::Error error = commitRegion(index, region);
2108 if (error.isError())
2109 {
2110 return error;
2111 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002112 }
Geoff Langef7b0162014-09-04 13:29:23 -04002113
2114 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002115}
2116
2117void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2118{
2119 // If there currently is a corresponding storage texture image, it has these parameters
2120 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2121 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2122 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2123 const GLenum storageFormat = getBaseLevelInternalFormat();
2124
2125 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2126
2127 if (mTexStorage)
2128 {
2129 const int storageLevels = mTexStorage->getLevelCount();
2130
2131 if ((level >= storageLevels && storageLevels != 0) ||
2132 width != storageWidth ||
2133 height != storageHeight ||
2134 depth != storageDepth ||
2135 internalformat != storageFormat) // Discard mismatched storage
2136 {
2137 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2138 {
2139 mImageArray[i]->markDirty();
2140 }
2141
2142 SafeDelete(mTexStorage);
2143 mDirtyImages = true;
2144 }
2145 }
2146}
2147
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002148gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002149{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002150 ASSERT(!index.hasLayer());
2151 GLint level = index.mipIndex;
2152
Brandon Jones78b1acd2014-07-15 15:33:07 -07002153 if (isValidLevel(level))
2154 {
2155 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04002156 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002157 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002158 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002159 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002160 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002161
2162 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002163 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002164
2165 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002166}
2167
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002168gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2169{
2170 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2171 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2172}
Brandon Jones142ec422014-07-16 10:31:30 -07002173
Jamie Madillcb83dc12014-09-29 10:46:12 -04002174gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2175{
2176 // The "layer" here does not apply to 3D images. We use one Image per mip.
2177 return gl::ImageIndex::Make3D(mip);
2178}
2179
Brandon Jones142ec422014-07-16 10:31:30 -07002180TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002181 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002182{
2183 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2184 {
2185 mLayerCounts[level] = 0;
2186 mImageArray[level] = NULL;
2187 }
2188}
2189
2190TextureD3D_2DArray::~TextureD3D_2DArray()
2191{
Austin Kinross69822602014-08-12 15:51:37 -07002192 // Delete the Images before the TextureStorage.
2193 // Images might be relying on the TextureStorage for some of their data.
2194 // 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 -07002195 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002196 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002197}
2198
Brandon Jones142ec422014-07-16 10:31:30 -07002199Image *TextureD3D_2DArray::getImage(int level, int layer) const
2200{
2201 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2202 ASSERT(layer < mLayerCounts[level]);
2203 return mImageArray[level][layer];
2204}
2205
Jamie Madillfeda4d22014-09-17 13:03:29 -04002206Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2207{
2208 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2209 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2210 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2211 return mImageArray[index.mipIndex][index.layerIndex];
2212}
2213
Brandon Jones142ec422014-07-16 10:31:30 -07002214GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2215{
2216 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2217 return mLayerCounts[level];
2218}
2219
Brandon Jones142ec422014-07-16 10:31:30 -07002220GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2221{
2222 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2223}
2224
2225GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2226{
2227 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2228}
2229
Brandon Jones142ec422014-07-16 10:31:30 -07002230GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2231{
2232 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2233}
2234
2235bool TextureD3D_2DArray::isDepth(GLint level) const
2236{
Geoff Lang5d601382014-07-22 15:14:06 -04002237 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002238}
2239
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002240gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2241 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2242 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002243{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002244 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2245
Geoff Lang5d601382014-07-22 15:14:06 -04002246 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2247
Brandon Jones142ec422014-07-16 10:31:30 -07002248 redefineImage(level, sizedInternalFormat, width, height, depth);
2249
Geoff Lang5d601382014-07-22 15:14:06 -04002250 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2251 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002252
2253 for (int i = 0; i < depth; i++)
2254 {
2255 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002256 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2257 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002258 if (error.isError())
2259 {
2260 return error;
2261 }
Brandon Jones142ec422014-07-16 10:31:30 -07002262 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002263
2264 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002265}
2266
Geoff Langb5348332014-09-02 13:16:34 -04002267gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2268 GLsizei width, GLsizei height, GLsizei depth,
2269 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002270{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002271 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2272
Brandon Jones142ec422014-07-16 10:31:30 -07002273 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2274 redefineImage(level, format, width, height, depth);
2275
Geoff Lang5d601382014-07-22 15:14:06 -04002276 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2277 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002278
2279 for (int i = 0; i < depth; i++)
2280 {
2281 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002282 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2283 if (error.isError())
2284 {
2285 return error;
2286 }
Brandon Jones142ec422014-07-16 10:31:30 -07002287 }
Geoff Langb5348332014-09-02 13:16:34 -04002288
2289 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002290}
2291
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002292gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2293 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2294 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002295{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002296 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2297
Geoff Lang5d601382014-07-22 15:14:06 -04002298 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2299 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002300
2301 for (int i = 0; i < depth; i++)
2302 {
2303 int layer = zoffset + i;
2304 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2305
Jamie Madillfeda4d22014-09-17 13:03:29 -04002306 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002307 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2308 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002309 if (error.isError())
2310 {
2311 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002312 }
2313 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002314
2315 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002316}
2317
Geoff Langb5348332014-09-02 13:16:34 -04002318gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2319 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2320 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002321{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002322 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2323
Geoff Lang5d601382014-07-22 15:14:06 -04002324 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2325 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002326
2327 for (int i = 0; i < depth; i++)
2328 {
2329 int layer = zoffset + i;
2330 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2331
Geoff Langb5348332014-09-02 13:16:34 -04002332 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2333 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002334 {
Geoff Langb5348332014-09-02 13:16:34 -04002335 return error;
2336 }
2337
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002338 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2339 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2340 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002341 if (error.isError())
2342 {
2343 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002344 }
2345 }
Geoff Langb5348332014-09-02 13:16:34 -04002346
2347 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002348}
2349
Geoff Langef7b0162014-09-04 13:29:23 -04002350gl::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 -07002351{
2352 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002353 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002354}
2355
Geoff Langef7b0162014-09-04 13:29:23 -04002356gl::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 -07002357{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002358 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2359
Brandon Jones142ec422014-07-16 10:31:30 -07002360 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2361 // the current level we're copying to is defined (with appropriate format, width & height)
2362 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2363
Jamie Madill82bf0c52014-10-03 11:50:53 -04002364 gl::Rectangle sourceRect(x, y, width, height);
2365
Brandon Jones142ec422014-07-16 10:31:30 -07002366 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2367 {
Geoff Langef7b0162014-09-04 13:29:23 -04002368 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2369 if (error.isError())
2370 {
2371 return error;
2372 }
2373
Brandon Jones142ec422014-07-16 10:31:30 -07002374 mDirtyImages = true;
2375 }
2376 else
2377 {
Geoff Langef7b0162014-09-04 13:29:23 -04002378 gl::Error error = ensureRenderTarget();
2379 if (error.isError())
2380 {
2381 return error;
2382 }
Brandon Jones142ec422014-07-16 10:31:30 -07002383
2384 if (isValidLevel(level))
2385 {
Geoff Langef7b0162014-09-04 13:29:23 -04002386 error = updateStorageLevel(level);
2387 if (error.isError())
2388 {
2389 return error;
2390 }
Brandon Jones142ec422014-07-16 10:31:30 -07002391
Geoff Langef7b0162014-09-04 13:29:23 -04002392 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2393 xoffset, yoffset, zoffset, mTexStorage, level);
2394 if (error.isError())
2395 {
2396 return error;
2397 }
Brandon Jones142ec422014-07-16 10:31:30 -07002398 }
2399 }
Geoff Langef7b0162014-09-04 13:29:23 -04002400 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002401}
2402
Geoff Lang1f8532b2014-09-05 09:46:13 -04002403gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002404{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002405 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2406
Brandon Jones142ec422014-07-16 10:31:30 -07002407 deleteImages();
2408
2409 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2410 {
2411 GLsizei levelWidth = std::max(1, width >> level);
2412 GLsizei levelHeight = std::max(1, height >> level);
2413
2414 mLayerCounts[level] = (level < levels ? depth : 0);
2415
2416 if (mLayerCounts[level] > 0)
2417 {
2418 // Create new images for this level
2419 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2420
2421 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2422 {
2423 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2424 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2425 levelHeight, 1, true);
2426 }
2427 }
2428 }
2429
Geoff Lang1f8532b2014-09-05 09:46:13 -04002430 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002431 bool renderTarget = IsRenderTargetUsage(mUsage);
2432 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002433
2434 gl::Error error = setCompleteTexStorage(storage);
2435 if (error.isError())
2436 {
2437 SafeDelete(storage);
2438 return error;
2439 }
2440
2441 mImmutable = true;
2442
2443 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002444}
2445
Brandon Jones6053a522014-07-25 16:22:09 -07002446void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002447{
Brandon Jones6053a522014-07-25 16:22:09 -07002448 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002449}
2450
Brandon Jones6053a522014-07-25 16:22:09 -07002451void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002452{
Brandon Jones6053a522014-07-25 16:22:09 -07002453 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002454}
2455
Brandon Jones6053a522014-07-25 16:22:09 -07002456
Jamie Madill4aa79e12014-09-29 10:46:14 -04002457void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002458{
2459 int baseWidth = getBaseLevelWidth();
2460 int baseHeight = getBaseLevelHeight();
2461 int baseDepth = getBaseLevelDepth();
2462 GLenum baseFormat = getBaseLevelInternalFormat();
2463
2464 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2465 int levelCount = mipLevels();
2466 for (int level = 1; level < levelCount; level++)
2467 {
2468 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2469 }
Brandon Jones142ec422014-07-16 10:31:30 -07002470}
2471
Jamie Madillac7579c2014-09-17 16:59:33 -04002472unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002473{
Geoff Langef7b0162014-09-04 13:29:23 -04002474 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002475}
2476
Jamie Madillac7579c2014-09-17 16:59:33 -04002477RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002478{
2479 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002480 gl::Error error = ensureRenderTarget();
2481 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002482 {
2483 return NULL;
2484 }
2485
Geoff Langef7b0162014-09-04 13:29:23 -04002486 error = updateStorageLevel(index.mipIndex);
2487 if (error.isError())
2488 {
2489 return NULL;
2490 }
2491
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002492 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002493}
2494
Geoff Langef7b0162014-09-04 13:29:23 -04002495gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002496{
2497 // Only initialize the first time this texture is used as a render target or shader resource
2498 if (mTexStorage)
2499 {
Geoff Langef7b0162014-09-04 13:29:23 -04002500 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002501 }
2502
2503 // do not attempt to create storage for nonexistant data
2504 if (!isLevelComplete(0))
2505 {
Geoff Langef7b0162014-09-04 13:29:23 -04002506 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002507 }
2508
2509 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2510
Geoff Langef7b0162014-09-04 13:29:23 -04002511 TextureStorage *storage = NULL;
2512 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2513 if (error.isError())
2514 {
2515 return error;
2516 }
2517
2518 error = setCompleteTexStorage(storage);
2519 if (error.isError())
2520 {
2521 SafeDelete(storage);
2522 return error;
2523 }
2524
Brandon Jones142ec422014-07-16 10:31:30 -07002525 ASSERT(mTexStorage);
2526
2527 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002528 error = updateStorage();
2529 if (error.isError())
2530 {
2531 return error;
2532 }
2533
2534 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002535}
2536
Geoff Langef7b0162014-09-04 13:29:23 -04002537gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002538{
2539 GLsizei width = getBaseLevelWidth();
2540 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002541 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002542 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002543
2544 ASSERT(width > 0 && height > 0 && depth > 0);
2545
2546 // use existing storage level count, when previously specified by TexStorage*D
2547 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2548
Geoff Langef7b0162014-09-04 13:29:23 -04002549 // TODO(geofflang): Verify storage creation succeeds
2550 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2551
2552 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002553}
2554
Geoff Langef7b0162014-09-04 13:29:23 -04002555gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002556{
2557 SafeDelete(mTexStorage);
2558 mTexStorage = newCompleteTexStorage;
2559 mDirtyImages = true;
2560
2561 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2562 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002563
2564 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002565}
2566
Geoff Langef7b0162014-09-04 13:29:23 -04002567gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002568{
2569 ASSERT(mTexStorage != NULL);
2570 GLint storageLevels = mTexStorage->getLevelCount();
2571 for (int level = 0; level < storageLevels; level++)
2572 {
2573 if (isLevelComplete(level))
2574 {
Geoff Langef7b0162014-09-04 13:29:23 -04002575 gl::Error error = updateStorageLevel(level);
2576 if (error.isError())
2577 {
2578 return error;
2579 }
Brandon Jones142ec422014-07-16 10:31:30 -07002580 }
2581 }
Geoff Langef7b0162014-09-04 13:29:23 -04002582
2583 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002584}
2585
Brandon Jones142ec422014-07-16 10:31:30 -07002586bool TextureD3D_2DArray::isValidLevel(int level) const
2587{
2588 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2589}
2590
2591bool TextureD3D_2DArray::isLevelComplete(int level) const
2592{
2593 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2594
2595 if (isImmutable())
2596 {
2597 return true;
2598 }
2599
2600 GLsizei width = getBaseLevelWidth();
2601 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002602 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002603
2604 if (width <= 0 || height <= 0 || layers <= 0)
2605 {
2606 return false;
2607 }
2608
2609 if (level == 0)
2610 {
2611 return true;
2612 }
2613
2614 if (getInternalFormat(level) != getInternalFormat(0))
2615 {
2616 return false;
2617 }
2618
2619 if (getWidth(level) != std::max(1, width >> level))
2620 {
2621 return false;
2622 }
2623
2624 if (getHeight(level) != std::max(1, height >> level))
2625 {
2626 return false;
2627 }
2628
Jamie Madill3269bcb2014-09-30 16:33:52 -04002629 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002630 {
2631 return false;
2632 }
2633
2634 return true;
2635}
2636
Geoff Langef7b0162014-09-04 13:29:23 -04002637gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002638{
2639 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2640 ASSERT(isLevelComplete(level));
2641
2642 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2643 {
2644 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2645 if (mImageArray[level][layer]->isDirty())
2646 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002647 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2648 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002649 gl::Error error = commitRegion(index, region);
2650 if (error.isError())
2651 {
2652 return error;
2653 }
Brandon Jones142ec422014-07-16 10:31:30 -07002654 }
2655 }
Geoff Langef7b0162014-09-04 13:29:23 -04002656
2657 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002658}
2659
2660void TextureD3D_2DArray::deleteImages()
2661{
2662 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2663 {
2664 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2665 {
2666 delete mImageArray[level][layer];
2667 }
2668 delete[] mImageArray[level];
2669 mImageArray[level] = NULL;
2670 mLayerCounts[level] = 0;
2671 }
2672}
2673
2674void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2675{
2676 // If there currently is a corresponding storage texture image, it has these parameters
2677 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2678 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002679 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002680 const GLenum storageFormat = getBaseLevelInternalFormat();
2681
2682 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2683 {
2684 delete mImageArray[level][layer];
2685 }
2686 delete[] mImageArray[level];
2687 mImageArray[level] = NULL;
2688 mLayerCounts[level] = depth;
2689
2690 if (depth > 0)
2691 {
2692 mImageArray[level] = new ImageD3D*[depth]();
2693
2694 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2695 {
2696 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2697 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2698 }
2699 }
2700
2701 if (mTexStorage)
2702 {
2703 const int storageLevels = mTexStorage->getLevelCount();
2704
2705 if ((level >= storageLevels && storageLevels != 0) ||
2706 width != storageWidth ||
2707 height != storageHeight ||
2708 depth != storageDepth ||
2709 internalformat != storageFormat) // Discard mismatched storage
2710 {
2711 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2712 {
2713 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2714 {
2715 mImageArray[level][layer]->markDirty();
2716 }
2717 }
2718
2719 delete mTexStorage;
2720 mTexStorage = NULL;
2721 mDirtyImages = true;
2722 }
2723 }
2724}
2725
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002726gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002727{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002728 ASSERT(index.hasLayer());
2729 GLint level = index.mipIndex;
2730 GLint layerTarget = index.layerIndex;
2731
Jamie Madill3269bcb2014-09-30 16:33:52 -04002732 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002733 {
2734 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill433bfd32014-10-20 12:07:36 -04002735 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002736 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002737 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002738 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002739 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002740
2741 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002742 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002743
2744 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002745}
2746
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002747gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2748{
2749 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2750}
2751
Jamie Madillcb83dc12014-09-29 10:46:12 -04002752gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2753{
2754 return gl::ImageIndex::Make2DArray(mip, layer);
2755}
2756
Brandon Jones78b1acd2014-07-15 15:33:07 -07002757}