blob: 85deb281a5e76adb1efa81dc8ef4a9c9487e9918 [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{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400296 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400297 return mTexStorage;
298}
299
Jamie Madill3269bcb2014-09-30 16:33:52 -0400300Image *TextureD3D::getBaseLevelImage() const
301{
302 return getImage(getImageIndex(0, 0));
303}
304
Jamie Madill4aa79e12014-09-29 10:46:14 -0400305void TextureD3D::generateMipmaps()
306{
Jamie Madill9aca0592014-10-06 16:26:59 -0400307 GLint mipCount = mipLevels();
308
309 if (mipCount == 1)
310 {
311 return; // no-op
312 }
313
314 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400315 initMipmapsImages();
316
317 // We know that all layers have the same dimension, for the texture to be complete
318 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400319
Jamie Madill9aca0592014-10-06 16:26:59 -0400320 // When making mipmaps with the setData workaround enabled, the texture storage has
321 // the image data already. For non-render-target storage, we have to pull it out into
322 // an image layer.
323 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
324 {
325 if (!mTexStorage->isRenderTarget())
326 {
327 // Copy from the storage mip 0 to Image mip 0
328 for (GLint layer = 0; layer < layerCount; ++layer)
329 {
330 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400331
Jamie Madill9aca0592014-10-06 16:26:59 -0400332 Image *image = getImage(srcIndex);
333 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
334 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
335 }
336 }
337 else
338 {
339 updateStorage();
340 }
341 }
342
343 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400344
345 for (GLint layer = 0; layer < layerCount; ++layer)
346 {
347 for (GLint mip = 1; mip < mipCount; ++mip)
348 {
349 ASSERT(getLayerCount(mip) == layerCount);
350
351 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
352 gl::ImageIndex destIndex = getImageIndex(mip, layer);
353
354 if (renderableStorage)
355 {
356 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400357 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400358 }
359 else
360 {
361 // CPU-side mipmapping
362 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
363 }
364 }
365 }
366}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700367
Jamie Madill135570a2014-09-30 16:33:51 -0400368bool TextureD3D::isBaseImageZeroSize() const
369{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400370 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400371
372 if (!baseImage || baseImage->getWidth() <= 0)
373 {
374 return true;
375 }
376
377 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
378 {
379 return true;
380 }
381
382 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
383 {
384 return true;
385 }
386
387 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
388 {
389 return true;
390 }
391
392 return false;
393}
394
Geoff Langef7b0162014-09-04 13:29:23 -0400395gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400396{
Geoff Langef7b0162014-09-04 13:29:23 -0400397 gl::Error error = initializeStorage(true);
398 if (error.isError())
399 {
400 return error;
401 }
Jamie Madill135570a2014-09-30 16:33:51 -0400402
403 if (!isBaseImageZeroSize())
404 {
405 ASSERT(mTexStorage);
406 if (!mTexStorage->isRenderTarget())
407 {
Geoff Langef7b0162014-09-04 13:29:23 -0400408 TextureStorage *newRenderTargetStorage = NULL;
409 error = createCompleteStorage(true, &newRenderTargetStorage);
410 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400411 {
Geoff Langef7b0162014-09-04 13:29:23 -0400412 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400413 }
414
Geoff Langef7b0162014-09-04 13:29:23 -0400415 error = mTexStorage->copyToStorage(newRenderTargetStorage);
416 if (error.isError())
417 {
418 SafeDelete(newRenderTargetStorage);
419 return error;
420 }
421
422 error = setCompleteTexStorage(newRenderTargetStorage);
423 if (error.isError())
424 {
425 SafeDelete(newRenderTargetStorage);
426 return error;
427 }
Jamie Madill135570a2014-09-30 16:33:51 -0400428 }
429 }
430
Geoff Langef7b0162014-09-04 13:29:23 -0400431 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400432}
433
Brandon Jones78b1acd2014-07-15 15:33:07 -0700434TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400435 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700436{
437 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
438 {
439 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
440 }
441}
442
443TextureD3D_2D::~TextureD3D_2D()
444{
Austin Kinross69822602014-08-12 15:51:37 -0700445 // Delete the Images before the TextureStorage.
446 // Images might be relying on the TextureStorage for some of their data.
447 // 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 -0700448 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
449 {
450 delete mImageArray[i];
451 }
Austin Kinross69822602014-08-12 15:51:37 -0700452
453 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700454}
455
Brandon Jonescef06ff2014-08-05 13:27:48 -0700456Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700457{
458 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700459 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700460 return mImageArray[level];
461}
462
Jamie Madillfeda4d22014-09-17 13:03:29 -0400463Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
464{
465 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400466 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400467 ASSERT(index.type == GL_TEXTURE_2D);
468 return mImageArray[index.mipIndex];
469}
470
Brandon Jonescef06ff2014-08-05 13:27:48 -0700471GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700472{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700473 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
474 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700475}
476
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700477GLsizei TextureD3D_2D::getWidth(GLint level) const
478{
479 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
480 return mImageArray[level]->getWidth();
481 else
482 return 0;
483}
484
485GLsizei TextureD3D_2D::getHeight(GLint level) const
486{
487 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
488 return mImageArray[level]->getHeight();
489 else
490 return 0;
491}
492
493GLenum TextureD3D_2D::getInternalFormat(GLint level) const
494{
495 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
496 return mImageArray[level]->getInternalFormat();
497 else
498 return GL_NONE;
499}
500
501GLenum TextureD3D_2D::getActualFormat(GLint level) const
502{
503 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
504 return mImageArray[level]->getActualFormat();
505 else
506 return GL_NONE;
507}
508
509bool TextureD3D_2D::isDepth(GLint level) const
510{
Geoff Lang5d601382014-07-22 15:14:06 -0400511 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700512}
513
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400514gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
515 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
516 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700517{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700518 ASSERT(target == GL_TEXTURE_2D && depth == 1);
519
Geoff Lang5d601382014-07-22 15:14:06 -0400520 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
521
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522 bool fastUnpacked = false;
523
Brandon Jonescef06ff2014-08-05 13:27:48 -0700524 redefineImage(level, sizedInternalFormat, width, height);
525
Jamie Madillba6bc952014-10-06 10:56:22 -0400526 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
527
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528 // Attempt a fast gpu copy of the pixel data to the surface
529 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
530 {
531 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400532 RenderTarget *destRenderTarget = NULL;
533 gl::Error error = getRenderTarget(index, &destRenderTarget);
534 if (error.isError())
535 {
536 return error;
537 }
538
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700539 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
540
Geoff Lang64f23f62014-09-10 14:40:12 -0400541 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
542 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400544 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700545 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400546
547 // Ensure we don't overwrite our newly initialized data
548 mImageArray[level]->markClean();
549
550 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551 }
552
553 if (!fastUnpacked)
554 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400555 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400556 if (error.isError())
557 {
558 return error;
559 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400561
562 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700563}
564
Geoff Langb5348332014-09-02 13:16:34 -0400565gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
566 GLsizei width, GLsizei height, GLsizei depth,
567 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700568{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700569 ASSERT(target == GL_TEXTURE_2D && depth == 1);
570
571 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
572 redefineImage(level, format, width, height);
573
Geoff Langb5348332014-09-02 13:16:34 -0400574 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575}
576
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400577gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
578 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
579 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700580{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700581 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
582
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583 bool fastUnpacked = false;
584
Jamie Madillac7579c2014-09-17 16:59:33 -0400585 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400586 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
588 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400589 RenderTarget *renderTarget = NULL;
590 gl::Error error = getRenderTarget(index, &renderTarget);
591 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700592 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400593 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700594 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400595
596 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
597 if (error.isError())
598 {
599 return error;
600 }
601
602 // Ensure we don't overwrite our newly initialized data
603 mImageArray[level]->markClean();
604
605 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606 }
607
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400608 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700609 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400610 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
611 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700612 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400613
614 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700615}
616
Geoff Langb5348332014-09-02 13:16:34 -0400617gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
618 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
619 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700620{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700621 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
622
Geoff Langb5348332014-09-02 13:16:34 -0400623 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
624 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625 {
Geoff Langb5348332014-09-02 13:16:34 -0400626 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700627 }
Geoff Langb5348332014-09-02 13:16:34 -0400628
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400629 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
630 gl::Box region(xoffset, yoffset, 0, width, height, 1);
631 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632}
633
Geoff Langef7b0162014-09-04 13:29:23 -0400634gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
635 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700637 ASSERT(target == GL_TEXTURE_2D);
638
639 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
640 redefineImage(level, sizedInternalFormat, width, height);
641
Jamie Madill82bf0c52014-10-03 11:50:53 -0400642 gl::Rectangle sourceRect(x, y, width, height);
643
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700644 if (!mImageArray[level]->isRenderableFormat())
645 {
Geoff Langef7b0162014-09-04 13:29:23 -0400646 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
647 if (error.isError())
648 {
649 return error;
650 }
651
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652 mDirtyImages = true;
653 }
654 else
655 {
Geoff Langef7b0162014-09-04 13:29:23 -0400656 gl::Error error = ensureRenderTarget();
657 if (error.isError())
658 {
659 return error;
660 }
661
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662 mImageArray[level]->markClean();
663
664 if (width != 0 && height != 0 && isValidLevel(level))
665 {
Geoff Langef7b0162014-09-04 13:29:23 -0400666 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
667 if (error.isError())
668 {
669 return error;
670 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671 }
672 }
Geoff Langef7b0162014-09-04 13:29:23 -0400673
674 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700675}
676
Geoff Langef7b0162014-09-04 13:29:23 -0400677gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
678 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700680 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
681
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700682 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
683 // the current level we're copying to is defined (with appropriate format, width & height)
684 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
685
Jamie Madill82bf0c52014-10-03 11:50:53 -0400686 gl::Rectangle sourceRect(x, y, width, height);
687
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
689 {
Geoff Langef7b0162014-09-04 13:29:23 -0400690 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
691 if (error.isError())
692 {
693 return error;
694 }
695
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700696 mDirtyImages = true;
697 }
698 else
699 {
Geoff Langef7b0162014-09-04 13:29:23 -0400700 gl::Error error = ensureRenderTarget();
701 if (error.isError())
702 {
703 return error;
704 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700705
706 if (isValidLevel(level))
707 {
Geoff Langef7b0162014-09-04 13:29:23 -0400708 error = updateStorageLevel(level);
709 if (error.isError())
710 {
711 return error;
712 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700713
Geoff Langef7b0162014-09-04 13:29:23 -0400714 error = mRenderer->copyImage2D(source, sourceRect,
715 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
716 xoffset, yoffset, mTexStorage, level);
717 if (error.isError())
718 {
719 return error;
720 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700721 }
722 }
Geoff Langef7b0162014-09-04 13:29:23 -0400723
724 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700725}
726
Geoff Lang1f8532b2014-09-05 09:46:13 -0400727gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700728{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700729 ASSERT(target == GL_TEXTURE_2D && depth == 1);
730
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700731 for (int level = 0; level < levels; level++)
732 {
733 GLsizei levelWidth = std::max(1, width >> level);
734 GLsizei levelHeight = std::max(1, height >> level);
735 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
736 }
737
738 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
739 {
740 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
741 }
742
Geoff Lang1f8532b2014-09-05 09:46:13 -0400743 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400744 bool renderTarget = IsRenderTargetUsage(mUsage);
745 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400746
747 gl::Error error = setCompleteTexStorage(storage);
748 if (error.isError())
749 {
750 SafeDelete(storage);
751 return error;
752 }
753
754 mImmutable = true;
755
756 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700757}
758
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700759void TextureD3D_2D::bindTexImage(egl::Surface *surface)
760{
761 GLenum internalformat = surface->getFormat();
762
763 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
764
765 if (mTexStorage)
766 {
767 SafeDelete(mTexStorage);
768 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400769
770 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700771
772 mDirtyImages = true;
773}
774
775void TextureD3D_2D::releaseTexImage()
776{
777 if (mTexStorage)
778 {
779 SafeDelete(mTexStorage);
780 }
781
782 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
783 {
784 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
785 }
786}
787
Jamie Madill4aa79e12014-09-29 10:46:14 -0400788void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700789{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700790 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700791 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792 for (int level = 1; level < levelCount; level++)
793 {
794 redefineImage(level, getBaseLevelInternalFormat(),
795 std::max(getBaseLevelWidth() >> level, 1),
796 std::max(getBaseLevelHeight() >> level, 1));
797 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700798}
799
Jamie Madillac7579c2014-09-17 16:59:33 -0400800unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700801{
Jamie Madillac7579c2014-09-17 16:59:33 -0400802 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400803 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700804}
805
Geoff Lang64f23f62014-09-10 14:40:12 -0400806gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700807{
Jamie Madillac7579c2014-09-17 16:59:33 -0400808 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700809
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700810 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400811 gl::Error error = ensureRenderTarget();
812 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400814 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700815 }
816
Geoff Langef7b0162014-09-04 13:29:23 -0400817 error = updateStorageLevel(index.mipIndex);
818 if (error.isError())
819 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400820 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400821 }
822
Geoff Lang64f23f62014-09-10 14:40:12 -0400823 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700824}
825
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700826bool TextureD3D_2D::isValidLevel(int level) const
827{
828 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
829}
830
831bool TextureD3D_2D::isLevelComplete(int level) const
832{
833 if (isImmutable())
834 {
835 return true;
836 }
837
Brandon Jones78b1acd2014-07-15 15:33:07 -0700838 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700839
840 GLsizei width = baseImage->getWidth();
841 GLsizei height = baseImage->getHeight();
842
843 if (width <= 0 || height <= 0)
844 {
845 return false;
846 }
847
848 // The base image level is complete if the width and height are positive
849 if (level == 0)
850 {
851 return true;
852 }
853
854 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700855 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700856
857 if (image->getInternalFormat() != baseImage->getInternalFormat())
858 {
859 return false;
860 }
861
862 if (image->getWidth() != std::max(1, width >> level))
863 {
864 return false;
865 }
866
867 if (image->getHeight() != std::max(1, height >> level))
868 {
869 return false;
870 }
871
872 return true;
873}
874
875// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400876gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700877{
878 // Only initialize the first time this texture is used as a render target or shader resource
879 if (mTexStorage)
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 // do not attempt to create storage for nonexistant data
885 if (!isLevelComplete(0))
886 {
Geoff Langef7b0162014-09-04 13:29:23 -0400887 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700888 }
889
890 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
891
Geoff Langef7b0162014-09-04 13:29:23 -0400892 TextureStorage *storage = NULL;
893 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
894 if (error.isError())
895 {
896 return error;
897 }
898
899 error = setCompleteTexStorage(storage);
900 if (error.isError())
901 {
902 SafeDelete(storage);
903 return error;
904 }
905
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700906 ASSERT(mTexStorage);
907
908 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400909 error = updateStorage();
910 if (error.isError())
911 {
912 return error;
913 }
914
915 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700916}
917
Geoff Langef7b0162014-09-04 13:29:23 -0400918gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919{
920 GLsizei width = getBaseLevelWidth();
921 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400922 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700923
924 ASSERT(width > 0 && height > 0);
925
926 // use existing storage level count, when previously specified by TexStorage*D
927 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
928
Geoff Langef7b0162014-09-04 13:29:23 -0400929 // TODO(geofflang): Determine if the texture creation succeeded
930 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
931
932 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700933}
934
Geoff Langef7b0162014-09-04 13:29:23 -0400935gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700936{
Geoff Langef7b0162014-09-04 13:29:23 -0400937 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700938 {
Geoff Langef7b0162014-09-04 13:29:23 -0400939 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700940 {
Geoff Langef7b0162014-09-04 13:29:23 -0400941 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
942 if (error.isError())
943 {
944 return error;
945 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700946 }
947 }
948
Geoff Langef7b0162014-09-04 13:29:23 -0400949 SafeDelete(mTexStorage);
950 mTexStorage = newCompleteTexStorage;
951
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700952 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400953
954 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700955}
956
Geoff Langef7b0162014-09-04 13:29:23 -0400957gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700958{
959 ASSERT(mTexStorage != NULL);
960 GLint storageLevels = mTexStorage->getLevelCount();
961 for (int level = 0; level < storageLevels; level++)
962 {
963 if (mImageArray[level]->isDirty() && isLevelComplete(level))
964 {
Geoff Langef7b0162014-09-04 13:29:23 -0400965 gl::Error error = updateStorageLevel(level);
966 if (error.isError())
967 {
968 return error;
969 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700970 }
971 }
Geoff Langef7b0162014-09-04 13:29:23 -0400972
973 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700974}
975
Geoff Langef7b0162014-09-04 13:29:23 -0400976gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700977{
978 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
979 ASSERT(isLevelComplete(level));
980
981 if (mImageArray[level]->isDirty())
982 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400983 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
984 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -0400985 gl::Error error = commitRegion(index, region);
986 if (error.isError())
987 {
988 return error;
989 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990 }
Geoff Langef7b0162014-09-04 13:29:23 -0400991
992 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700993}
994
995void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
996{
997 // If there currently is a corresponding storage texture image, it has these parameters
998 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
999 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1000 const GLenum storageFormat = getBaseLevelInternalFormat();
1001
1002 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1003
1004 if (mTexStorage)
1005 {
1006 const int storageLevels = mTexStorage->getLevelCount();
1007
1008 if ((level >= storageLevels && storageLevels != 0) ||
1009 width != storageWidth ||
1010 height != storageHeight ||
1011 internalformat != storageFormat) // Discard mismatched storage
1012 {
1013 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1014 {
1015 mImageArray[i]->markDirty();
1016 }
1017
1018 SafeDelete(mTexStorage);
1019 mDirtyImages = true;
1020 }
1021 }
1022}
1023
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001024gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001025{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001026 ASSERT(!index.hasLayer());
1027 GLint level = index.mipIndex;
1028
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001029 if (isValidLevel(level))
1030 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001031 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001032 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001033 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001034 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001035 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001036 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001037
1038 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001039 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001040
1041 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001042}
1043
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001044gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1045{
1046 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1047}
Brandon Jones0511e802014-07-14 16:27:26 -07001048
Jamie Madillcb83dc12014-09-29 10:46:12 -04001049gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1050{
1051 // "layer" does not apply to 2D Textures.
1052 return gl::ImageIndex::Make2D(mip);
1053}
1054
Brandon Jones78b1acd2014-07-15 15:33:07 -07001055TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001056 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001057{
1058 for (int i = 0; i < 6; i++)
1059 {
1060 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1061 {
1062 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1063 }
1064 }
1065}
1066
1067TextureD3D_Cube::~TextureD3D_Cube()
1068{
Austin Kinross69822602014-08-12 15:51:37 -07001069 // Delete the Images before the TextureStorage.
1070 // Images might be relying on the TextureStorage for some of their data.
1071 // 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 -07001072 for (int i = 0; i < 6; i++)
1073 {
1074 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1075 {
1076 SafeDelete(mImageArray[i][j]);
1077 }
1078 }
Austin Kinross69822602014-08-12 15:51:37 -07001079
1080 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001081}
1082
Brandon Jonescef06ff2014-08-05 13:27:48 -07001083Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001084{
1085 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001086 ASSERT(layer < 6);
1087 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001088}
1089
Jamie Madillfeda4d22014-09-17 13:03:29 -04001090Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1091{
1092 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1093 ASSERT(index.layerIndex < 6);
1094 return mImageArray[index.layerIndex][index.mipIndex];
1095}
1096
Brandon Jonescef06ff2014-08-05 13:27:48 -07001097GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001098{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001099 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1100 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001101}
1102
Brandon Jonescef06ff2014-08-05 13:27:48 -07001103GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001104{
1105 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001106 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001107 else
1108 return GL_NONE;
1109}
1110
Brandon Jonescef06ff2014-08-05 13:27:48 -07001111bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001112{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001113 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001114}
1115
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001116gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1117 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1118 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001119{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001120 ASSERT(depth == 1);
1121
Geoff Lang5d601382014-07-22 15:14:06 -04001122 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001123 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001124
Jamie Madillba6bc952014-10-06 10:56:22 -04001125 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001126
Jamie Madillba6bc952014-10-06 10:56:22 -04001127 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001128}
1129
Geoff Langb5348332014-09-02 13:16:34 -04001130gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1131 GLsizei width, GLsizei height, GLsizei depth,
1132 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001133{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001134 ASSERT(depth == 1);
1135
Brandon Jones0511e802014-07-14 16:27:26 -07001136 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001137 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1138
Brandon Jones0511e802014-07-14 16:27:26 -07001139 redefineImage(faceIndex, level, format, width, height);
1140
Geoff Langb5348332014-09-02 13:16:34 -04001141 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001142}
1143
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001144gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1145 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1146 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001147{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001148 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001149 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001150 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001151}
1152
Geoff Langb5348332014-09-02 13:16:34 -04001153gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1154 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1155 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001156{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001157 ASSERT(depth == 1 && zoffset == 0);
1158
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001159 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001160
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001161 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 -04001162 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001163 {
Geoff Langb5348332014-09-02 13:16:34 -04001164 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001165 }
Geoff Langb5348332014-09-02 13:16:34 -04001166
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001167 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1168 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001169}
1170
Geoff Langef7b0162014-09-04 13:29:23 -04001171gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1172 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001173{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001174 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001175 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1176
Brandon Jones0511e802014-07-14 16:27:26 -07001177 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1178
Jamie Madill82bf0c52014-10-03 11:50:53 -04001179 gl::Rectangle sourceRect(x, y, width, height);
1180
Brandon Jones0511e802014-07-14 16:27:26 -07001181 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1182 {
Geoff Langef7b0162014-09-04 13:29:23 -04001183 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1184 if (error.isError())
1185 {
1186 return error;
1187 }
1188
Brandon Jones0511e802014-07-14 16:27:26 -07001189 mDirtyImages = true;
1190 }
1191 else
1192 {
Geoff Langef7b0162014-09-04 13:29:23 -04001193 gl::Error error = ensureRenderTarget();
1194 if (error.isError())
1195 {
1196 return error;
1197 }
1198
Brandon Jones0511e802014-07-14 16:27:26 -07001199 mImageArray[faceIndex][level]->markClean();
1200
1201 ASSERT(width == height);
1202
1203 if (width > 0 && isValidFaceLevel(faceIndex, level))
1204 {
Geoff Langef7b0162014-09-04 13:29:23 -04001205 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1206 if (error.isError())
1207 {
1208 return error;
1209 }
Brandon Jones0511e802014-07-14 16:27:26 -07001210 }
1211 }
Geoff Langef7b0162014-09-04 13:29:23 -04001212
1213 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001214}
1215
Geoff Langef7b0162014-09-04 13:29:23 -04001216gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1217 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001218{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001219 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001220
1221 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1222 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1223 // rely on the "getBaseLevel*" methods reliably otherwise.
1224 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1225
Jamie Madill82bf0c52014-10-03 11:50:53 -04001226 gl::Rectangle sourceRect(x, y, width, height);
1227
Brandon Jones0511e802014-07-14 16:27:26 -07001228 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1229 {
Geoff Langef7b0162014-09-04 13:29:23 -04001230 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1231 if (error.isError())
1232 {
1233 return error;
1234 }
1235
Brandon Jones0511e802014-07-14 16:27:26 -07001236 mDirtyImages = true;
1237 }
1238 else
1239 {
Geoff Langef7b0162014-09-04 13:29:23 -04001240 gl::Error error = ensureRenderTarget();
1241 if (error.isError())
1242 {
1243 return error;
1244 }
Brandon Jones0511e802014-07-14 16:27:26 -07001245
1246 if (isValidFaceLevel(faceIndex, level))
1247 {
Geoff Langef7b0162014-09-04 13:29:23 -04001248 error = updateStorageFaceLevel(faceIndex, level);
1249 if (error.isError())
1250 {
1251 return error;
1252 }
Brandon Jones0511e802014-07-14 16:27:26 -07001253
Geoff Langef7b0162014-09-04 13:29:23 -04001254 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1255 xoffset, yoffset, mTexStorage, target, level);
1256 if (error.isError())
1257 {
1258 return error;
1259 }
Brandon Jones0511e802014-07-14 16:27:26 -07001260 }
1261 }
Geoff Langef7b0162014-09-04 13:29:23 -04001262
1263 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001264}
1265
Geoff Lang1f8532b2014-09-05 09:46:13 -04001266gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001267{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001268 ASSERT(width == height);
1269 ASSERT(depth == 1);
1270
Brandon Jones0511e802014-07-14 16:27:26 -07001271 for (int level = 0; level < levels; level++)
1272 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001273 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001274 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1275 {
1276 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1277 }
1278 }
1279
1280 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1281 {
1282 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1283 {
1284 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1285 }
1286 }
1287
Geoff Lang1f8532b2014-09-05 09:46:13 -04001288 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001289 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001290 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001291
1292 gl::Error error = setCompleteTexStorage(storage);
1293 if (error.isError())
1294 {
1295 SafeDelete(storage);
1296 return error;
1297 }
1298
1299 mImmutable = true;
1300
1301 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001302}
1303
Brandon Jones0511e802014-07-14 16:27:26 -07001304// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1305bool TextureD3D_Cube::isCubeComplete() const
1306{
1307 int baseWidth = getBaseLevelWidth();
1308 int baseHeight = getBaseLevelHeight();
1309 GLenum baseFormat = getBaseLevelInternalFormat();
1310
1311 if (baseWidth <= 0 || baseWidth != baseHeight)
1312 {
1313 return false;
1314 }
1315
1316 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1317 {
1318 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1319
1320 if (faceBaseImage.getWidth() != baseWidth ||
1321 faceBaseImage.getHeight() != baseHeight ||
1322 faceBaseImage.getInternalFormat() != baseFormat )
1323 {
1324 return false;
1325 }
1326 }
1327
1328 return true;
1329}
1330
Brandon Jones6053a522014-07-25 16:22:09 -07001331void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1332{
1333 UNREACHABLE();
1334}
1335
1336void TextureD3D_Cube::releaseTexImage()
1337{
1338 UNREACHABLE();
1339}
1340
1341
Jamie Madill4aa79e12014-09-29 10:46:14 -04001342void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001343{
1344 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1345 int levelCount = mipLevels();
1346 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1347 {
1348 for (int level = 1; level < levelCount; level++)
1349 {
1350 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1351 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1352 }
1353 }
Brandon Jones0511e802014-07-14 16:27:26 -07001354}
1355
Jamie Madillac7579c2014-09-17 16:59:33 -04001356unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001357{
Geoff Langef7b0162014-09-04 13:29:23 -04001358 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001359}
1360
Geoff Lang64f23f62014-09-10 14:40:12 -04001361gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001362{
Jamie Madillac7579c2014-09-17 16:59:33 -04001363 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001364
1365 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001366 gl::Error error = ensureRenderTarget();
1367 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001368 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001369 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001370 }
1371
Geoff Langef7b0162014-09-04 13:29:23 -04001372 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1373 if (error.isError())
1374 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001375 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001376 }
1377
Geoff Lang64f23f62014-09-10 14:40:12 -04001378 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001379}
1380
Geoff Langef7b0162014-09-04 13:29:23 -04001381gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001382{
1383 // Only initialize the first time this texture is used as a render target or shader resource
1384 if (mTexStorage)
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 // do not attempt to create storage for nonexistant data
1390 if (!isFaceLevelComplete(0, 0))
1391 {
Geoff Langef7b0162014-09-04 13:29:23 -04001392 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001393 }
1394
1395 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1396
Geoff Langef7b0162014-09-04 13:29:23 -04001397 TextureStorage *storage = NULL;
1398 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1399 if (error.isError())
1400 {
1401 return error;
1402 }
1403
1404 error = setCompleteTexStorage(storage);
1405 if (error.isError())
1406 {
1407 SafeDelete(storage);
1408 return error;
1409 }
1410
Brandon Jones0511e802014-07-14 16:27:26 -07001411 ASSERT(mTexStorage);
1412
1413 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001414 error = updateStorage();
1415 if (error.isError())
1416 {
1417 return error;
1418 }
1419
1420 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001421}
1422
Geoff Langef7b0162014-09-04 13:29:23 -04001423gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001424{
1425 GLsizei size = getBaseLevelWidth();
1426
1427 ASSERT(size > 0);
1428
1429 // use existing storage level count, when previously specified by TexStorage*D
1430 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1431
Geoff Langef7b0162014-09-04 13:29:23 -04001432 // TODO (geofflang): detect if storage creation succeeded
1433 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1434
1435 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001436}
1437
Geoff Langef7b0162014-09-04 13:29:23 -04001438gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001439{
Geoff Langef7b0162014-09-04 13:29:23 -04001440 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001441 {
1442 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1443 {
Geoff Langef7b0162014-09-04 13:29:23 -04001444 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001445 {
Geoff Langef7b0162014-09-04 13:29:23 -04001446 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1447 if (error.isError())
1448 {
1449 return error;
1450 }
Brandon Jones0511e802014-07-14 16:27:26 -07001451 }
1452 }
1453 }
1454
Geoff Langef7b0162014-09-04 13:29:23 -04001455 SafeDelete(mTexStorage);
1456 mTexStorage = newCompleteTexStorage;
1457
Brandon Jones0511e802014-07-14 16:27:26 -07001458 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001459 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001460}
1461
Geoff Langef7b0162014-09-04 13:29:23 -04001462gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001463{
1464 ASSERT(mTexStorage != NULL);
1465 GLint storageLevels = mTexStorage->getLevelCount();
1466 for (int face = 0; face < 6; face++)
1467 {
1468 for (int level = 0; level < storageLevels; level++)
1469 {
1470 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1471 {
Geoff Langef7b0162014-09-04 13:29:23 -04001472 gl::Error error = updateStorageFaceLevel(face, level);
1473 if (error.isError())
1474 {
1475 return error;
1476 }
Brandon Jones0511e802014-07-14 16:27:26 -07001477 }
1478 }
1479 }
Geoff Langef7b0162014-09-04 13:29:23 -04001480
1481 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001482}
1483
Brandon Jones0511e802014-07-14 16:27:26 -07001484bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1485{
1486 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1487}
1488
Brandon Jones0511e802014-07-14 16:27:26 -07001489bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1490{
1491 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1492
1493 if (isImmutable())
1494 {
1495 return true;
1496 }
1497
1498 int baseSize = getBaseLevelWidth();
1499
1500 if (baseSize <= 0)
1501 {
1502 return false;
1503 }
1504
1505 // "isCubeComplete" checks for base level completeness and we must call that
1506 // to determine if any face at level 0 is complete. We omit that check here
1507 // to avoid re-checking cube-completeness for every face at level 0.
1508 if (level == 0)
1509 {
1510 return true;
1511 }
1512
1513 // Check that non-zero levels are consistent with the base level.
1514 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1515
1516 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1517 {
1518 return false;
1519 }
1520
1521 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1522 {
1523 return false;
1524 }
1525
1526 return true;
1527}
1528
Geoff Langef7b0162014-09-04 13:29:23 -04001529gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001530{
1531 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1532 ImageD3D *image = mImageArray[faceIndex][level];
1533
1534 if (image->isDirty())
1535 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001536 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1537 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1538 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001539 gl::Error error = commitRegion(index, region);
1540 if (error.isError())
1541 {
1542 return error;
1543 }
Brandon Jones0511e802014-07-14 16:27:26 -07001544 }
Geoff Langef7b0162014-09-04 13:29:23 -04001545
1546 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001547}
1548
1549void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1550{
1551 // If there currently is a corresponding storage texture image, it has these parameters
1552 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1553 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1554 const GLenum storageFormat = getBaseLevelInternalFormat();
1555
1556 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1557
1558 if (mTexStorage)
1559 {
1560 const int storageLevels = mTexStorage->getLevelCount();
1561
1562 if ((level >= storageLevels && storageLevels != 0) ||
1563 width != storageWidth ||
1564 height != storageHeight ||
1565 internalformat != storageFormat) // Discard mismatched storage
1566 {
1567 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1568 {
1569 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1570 {
1571 mImageArray[faceIndex][level]->markDirty();
1572 }
1573 }
1574
1575 SafeDelete(mTexStorage);
1576
1577 mDirtyImages = true;
1578 }
1579 }
1580}
1581
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001582gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001583{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001584 ASSERT(index.hasLayer());
1585
1586 GLint level = index.mipIndex;
1587 int faceIndex = static_cast<int>(index.layerIndex);
1588
Brandon Jones0511e802014-07-14 16:27:26 -07001589 if (isValidFaceLevel(faceIndex, level))
1590 {
1591 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001592 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001593 if (error.isError())
1594 {
1595 return error;
1596 }
1597
1598 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001599 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001600
1601 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001602}
1603
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001604gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1605{
1606 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1607}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001608
Jamie Madillcb83dc12014-09-29 10:46:12 -04001609gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1610{
1611 // The "layer" of the image index corresponds to the cube face
1612 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1613}
1614
Brandon Jones78b1acd2014-07-15 15:33:07 -07001615TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001616 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001617{
1618 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1619 {
1620 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1621 }
1622}
1623
1624TextureD3D_3D::~TextureD3D_3D()
1625{
Austin Kinross69822602014-08-12 15:51:37 -07001626 // Delete the Images before the TextureStorage.
1627 // Images might be relying on the TextureStorage for some of their data.
1628 // 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 -07001629 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1630 {
1631 delete mImageArray[i];
1632 }
Austin Kinross69822602014-08-12 15:51:37 -07001633
1634 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001635}
1636
Brandon Jonescef06ff2014-08-05 13:27:48 -07001637Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001638{
1639 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001640 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001641 return mImageArray[level];
1642}
1643
Jamie Madillfeda4d22014-09-17 13:03:29 -04001644Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1645{
1646 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001647 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001648 ASSERT(index.type == GL_TEXTURE_3D);
1649 return mImageArray[index.mipIndex];
1650}
1651
Brandon Jonescef06ff2014-08-05 13:27:48 -07001652GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001653{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001654 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1655 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656}
1657
Brandon Jones78b1acd2014-07-15 15:33:07 -07001658GLsizei TextureD3D_3D::getWidth(GLint level) const
1659{
1660 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1661 return mImageArray[level]->getWidth();
1662 else
1663 return 0;
1664}
1665
1666GLsizei TextureD3D_3D::getHeight(GLint level) const
1667{
1668 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1669 return mImageArray[level]->getHeight();
1670 else
1671 return 0;
1672}
1673
1674GLsizei TextureD3D_3D::getDepth(GLint level) const
1675{
1676 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1677 return mImageArray[level]->getDepth();
1678 else
1679 return 0;
1680}
1681
1682GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1683{
1684 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1685 return mImageArray[level]->getInternalFormat();
1686 else
1687 return GL_NONE;
1688}
1689
1690bool TextureD3D_3D::isDepth(GLint level) const
1691{
Geoff Lang5d601382014-07-22 15:14:06 -04001692 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001693}
1694
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001695gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1696 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1697 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001698{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001699 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001700 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1701
Brandon Jones78b1acd2014-07-15 15:33:07 -07001702 redefineImage(level, sizedInternalFormat, width, height, depth);
1703
1704 bool fastUnpacked = false;
1705
Jamie Madillba6bc952014-10-06 10:56:22 -04001706 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1707
Brandon Jones78b1acd2014-07-15 15:33:07 -07001708 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1709 if (isFastUnpackable(unpack, sizedInternalFormat))
1710 {
1711 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001712 RenderTarget *destRenderTarget = NULL;
1713 gl::Error error = getRenderTarget(index, &destRenderTarget);
1714 if (error.isError())
1715 {
1716 return error;
1717 }
1718
Brandon Jones78b1acd2014-07-15 15:33:07 -07001719 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1720
Geoff Lang64f23f62014-09-10 14:40:12 -04001721 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1722 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001723 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001724 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001725 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001726
1727 // Ensure we don't overwrite our newly initialized data
1728 mImageArray[level]->markClean();
1729
1730 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001731 }
1732
1733 if (!fastUnpacked)
1734 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001735 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001736 if (error.isError())
1737 {
1738 return error;
1739 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001740 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001741
1742 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001743}
1744
Geoff Langb5348332014-09-02 13:16:34 -04001745gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1746 GLsizei width, GLsizei height,GLsizei depth,
1747 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001748{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001749 ASSERT(target == GL_TEXTURE_3D);
1750
Brandon Jones78b1acd2014-07-15 15:33:07 -07001751 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1752 redefineImage(level, format, width, height, depth);
1753
Geoff Langb5348332014-09-02 13:16:34 -04001754 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001755}
1756
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001757gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1758 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1759 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001760{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001761 ASSERT(target == GL_TEXTURE_3D);
1762
Brandon Jones78b1acd2014-07-15 15:33:07 -07001763 bool fastUnpacked = false;
1764
Jamie Madillac7579c2014-09-17 16:59:33 -04001765 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1766
Brandon Jones78b1acd2014-07-15 15:33:07 -07001767 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1768 if (isFastUnpackable(unpack, getInternalFormat(level)))
1769 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001770 RenderTarget *destRenderTarget = NULL;
1771 gl::Error error = getRenderTarget(index, &destRenderTarget);
1772 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001773 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001774 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001775 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001776
1777 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1778 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1779 if (error.isError())
1780 {
1781 return error;
1782 }
1783
1784 // Ensure we don't overwrite our newly initialized data
1785 mImageArray[level]->markClean();
1786
1787 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001788 }
1789
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001790 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001792 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1793 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001794 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001795
1796 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001797}
1798
Geoff Langb5348332014-09-02 13:16:34 -04001799gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1800 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1801 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001803 ASSERT(target == GL_TEXTURE_3D);
1804
Geoff Langb5348332014-09-02 13:16:34 -04001805 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1806 format, imageSize, pixels, mImageArray[level]);
1807 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001808 {
Geoff Langb5348332014-09-02 13:16:34 -04001809 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001810 }
Geoff Langb5348332014-09-02 13:16:34 -04001811
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001812 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1813 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1814 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815}
1816
Geoff Langef7b0162014-09-04 13:29:23 -04001817gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1818 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001819{
1820 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001821 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001822}
1823
Geoff Langef7b0162014-09-04 13:29:23 -04001824gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1825 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001826{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001827 ASSERT(target == GL_TEXTURE_3D);
1828
Brandon Jones78b1acd2014-07-15 15:33:07 -07001829 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1830 // the current level we're copying to is defined (with appropriate format, width & height)
1831 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1832
Jamie Madill82bf0c52014-10-03 11:50:53 -04001833 gl::Rectangle sourceRect(x, y, width, height);
1834
Brandon Jones78b1acd2014-07-15 15:33:07 -07001835 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1836 {
Geoff Langef7b0162014-09-04 13:29:23 -04001837 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1838 if (error.isError())
1839 {
1840 return error;
1841 }
1842
Brandon Jones78b1acd2014-07-15 15:33:07 -07001843 mDirtyImages = true;
1844 }
1845 else
1846 {
Geoff Langef7b0162014-09-04 13:29:23 -04001847 gl::Error error = ensureRenderTarget();
1848 if (error.isError())
1849 {
1850 return error;
1851 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001852
1853 if (isValidLevel(level))
1854 {
Geoff Langef7b0162014-09-04 13:29:23 -04001855 error = updateStorageLevel(level);
1856 if (error.isError())
1857 {
1858 return error;
1859 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001860
Geoff Langef7b0162014-09-04 13:29:23 -04001861 error = mRenderer->copyImage3D(source, sourceRect,
1862 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1863 xoffset, yoffset, zoffset, mTexStorage, level);
1864 if (error.isError())
1865 {
1866 return error;
1867 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001868 }
1869 }
Geoff Langef7b0162014-09-04 13:29:23 -04001870
1871 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001872}
1873
Geoff Lang1f8532b2014-09-05 09:46:13 -04001874gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001875{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001876 ASSERT(target == GL_TEXTURE_3D);
1877
Brandon Jones78b1acd2014-07-15 15:33:07 -07001878 for (int level = 0; level < levels; level++)
1879 {
1880 GLsizei levelWidth = std::max(1, width >> level);
1881 GLsizei levelHeight = std::max(1, height >> level);
1882 GLsizei levelDepth = std::max(1, depth >> level);
1883 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1884 }
1885
1886 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1887 {
1888 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1889 }
1890
Geoff Lang1f8532b2014-09-05 09:46:13 -04001891 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001892 bool renderTarget = IsRenderTargetUsage(mUsage);
1893 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001894
1895 gl::Error error = setCompleteTexStorage(storage);
1896 if (error.isError())
1897 {
1898 SafeDelete(storage);
1899 return error;
1900 }
1901
1902 mImmutable = true;
1903
1904 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001905}
1906
Brandon Jones6053a522014-07-25 16:22:09 -07001907void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001908{
Brandon Jones6053a522014-07-25 16:22:09 -07001909 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001910}
1911
Brandon Jones6053a522014-07-25 16:22:09 -07001912void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001913{
Brandon Jones6053a522014-07-25 16:22:09 -07001914 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001915}
1916
Brandon Jones6053a522014-07-25 16:22:09 -07001917
Jamie Madill4aa79e12014-09-29 10:46:14 -04001918void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001919{
1920 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1921 int levelCount = mipLevels();
1922 for (int level = 1; level < levelCount; level++)
1923 {
1924 redefineImage(level, getBaseLevelInternalFormat(),
1925 std::max(getBaseLevelWidth() >> level, 1),
1926 std::max(getBaseLevelHeight() >> level, 1),
1927 std::max(getBaseLevelDepth() >> level, 1));
1928 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001929}
1930
Jamie Madillac7579c2014-09-17 16:59:33 -04001931unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001932{
Geoff Langef7b0162014-09-04 13:29:23 -04001933 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001934}
1935
Geoff Lang64f23f62014-09-10 14:40:12 -04001936gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001937{
1938 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001939 gl::Error error = ensureRenderTarget();
1940 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001941 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001942 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001943 }
1944
Jamie Madillac7579c2014-09-17 16:59:33 -04001945 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001946 {
Geoff Langef7b0162014-09-04 13:29:23 -04001947 error = updateStorage();
1948 if (error.isError())
1949 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001950 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001951 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001952 }
1953 else
1954 {
Geoff Langef7b0162014-09-04 13:29:23 -04001955 error = updateStorageLevel(index.mipIndex);
1956 if (error.isError())
1957 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001958 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001959 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001960 }
1961
Geoff Lang64f23f62014-09-10 14:40:12 -04001962 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001963}
1964
Geoff Langef7b0162014-09-04 13:29:23 -04001965gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001966{
1967 // Only initialize the first time this texture is used as a render target or shader resource
1968 if (mTexStorage)
1969 {
Geoff Langef7b0162014-09-04 13:29:23 -04001970 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001971 }
1972
1973 // do not attempt to create storage for nonexistant data
1974 if (!isLevelComplete(0))
1975 {
Geoff Langef7b0162014-09-04 13:29:23 -04001976 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001977 }
1978
1979 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1980
Geoff Langef7b0162014-09-04 13:29:23 -04001981 rx::TextureStorage *storage = NULL;
1982 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1983 if (error.isError())
1984 {
1985 return error;
1986 }
1987
1988 error = setCompleteTexStorage(storage);
1989 if (error.isError())
1990 {
1991 SafeDelete(storage);
1992 return error;
1993 }
1994
Brandon Jones78b1acd2014-07-15 15:33:07 -07001995 ASSERT(mTexStorage);
1996
1997 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001998 error = updateStorage();
1999 if (error.isError())
2000 {
2001 return error;
2002 }
2003
2004 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002005}
2006
Geoff Langef7b0162014-09-04 13:29:23 -04002007gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002008{
2009 GLsizei width = getBaseLevelWidth();
2010 GLsizei height = getBaseLevelHeight();
2011 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002012 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002013
2014 ASSERT(width > 0 && height > 0 && depth > 0);
2015
2016 // use existing storage level count, when previously specified by TexStorage*D
2017 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2018
Geoff Langef7b0162014-09-04 13:29:23 -04002019 // TODO: Verify creation of the storage succeeded
2020 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2021
2022 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002023}
2024
Geoff Langef7b0162014-09-04 13:29:23 -04002025gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002026{
2027 SafeDelete(mTexStorage);
2028 mTexStorage = newCompleteTexStorage;
2029 mDirtyImages = true;
2030
2031 // We do not support managed 3D storage, as that is D3D9/ES2-only
2032 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002033
2034 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002035}
2036
Geoff Langef7b0162014-09-04 13:29:23 -04002037gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002038{
2039 ASSERT(mTexStorage != NULL);
2040 GLint storageLevels = mTexStorage->getLevelCount();
2041 for (int level = 0; level < storageLevels; level++)
2042 {
2043 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2044 {
Geoff Langef7b0162014-09-04 13:29:23 -04002045 gl::Error error = updateStorageLevel(level);
2046 if (error.isError())
2047 {
2048 return error;
2049 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002050 }
2051 }
Geoff Langef7b0162014-09-04 13:29:23 -04002052
2053 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002054}
2055
Brandon Jones78b1acd2014-07-15 15:33:07 -07002056bool TextureD3D_3D::isValidLevel(int level) const
2057{
2058 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2059}
2060
2061bool TextureD3D_3D::isLevelComplete(int level) const
2062{
2063 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2064
2065 if (isImmutable())
2066 {
2067 return true;
2068 }
2069
2070 GLsizei width = getBaseLevelWidth();
2071 GLsizei height = getBaseLevelHeight();
2072 GLsizei depth = getBaseLevelDepth();
2073
2074 if (width <= 0 || height <= 0 || depth <= 0)
2075 {
2076 return false;
2077 }
2078
2079 if (level == 0)
2080 {
2081 return true;
2082 }
2083
2084 ImageD3D *levelImage = mImageArray[level];
2085
2086 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2087 {
2088 return false;
2089 }
2090
2091 if (levelImage->getWidth() != std::max(1, width >> level))
2092 {
2093 return false;
2094 }
2095
2096 if (levelImage->getHeight() != std::max(1, height >> level))
2097 {
2098 return false;
2099 }
2100
2101 if (levelImage->getDepth() != std::max(1, depth >> level))
2102 {
2103 return false;
2104 }
2105
2106 return true;
2107}
2108
Geoff Langef7b0162014-09-04 13:29:23 -04002109gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002110{
2111 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2112 ASSERT(isLevelComplete(level));
2113
2114 if (mImageArray[level]->isDirty())
2115 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002116 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2117 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002118 gl::Error error = commitRegion(index, region);
2119 if (error.isError())
2120 {
2121 return error;
2122 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002123 }
Geoff Langef7b0162014-09-04 13:29:23 -04002124
2125 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002126}
2127
2128void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2129{
2130 // If there currently is a corresponding storage texture image, it has these parameters
2131 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2132 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2133 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2134 const GLenum storageFormat = getBaseLevelInternalFormat();
2135
2136 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2137
2138 if (mTexStorage)
2139 {
2140 const int storageLevels = mTexStorage->getLevelCount();
2141
2142 if ((level >= storageLevels && storageLevels != 0) ||
2143 width != storageWidth ||
2144 height != storageHeight ||
2145 depth != storageDepth ||
2146 internalformat != storageFormat) // Discard mismatched storage
2147 {
2148 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2149 {
2150 mImageArray[i]->markDirty();
2151 }
2152
2153 SafeDelete(mTexStorage);
2154 mDirtyImages = true;
2155 }
2156 }
2157}
2158
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002159gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002160{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002161 ASSERT(!index.hasLayer());
2162 GLint level = index.mipIndex;
2163
Brandon Jones78b1acd2014-07-15 15:33:07 -07002164 if (isValidLevel(level))
2165 {
2166 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04002167 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002168 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002169 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002170 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002171 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002172
2173 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002174 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002175
2176 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002177}
2178
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002179gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2180{
2181 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2182 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2183}
Brandon Jones142ec422014-07-16 10:31:30 -07002184
Jamie Madillcb83dc12014-09-29 10:46:12 -04002185gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2186{
2187 // The "layer" here does not apply to 3D images. We use one Image per mip.
2188 return gl::ImageIndex::Make3D(mip);
2189}
2190
Brandon Jones142ec422014-07-16 10:31:30 -07002191TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002192 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002193{
2194 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2195 {
2196 mLayerCounts[level] = 0;
2197 mImageArray[level] = NULL;
2198 }
2199}
2200
2201TextureD3D_2DArray::~TextureD3D_2DArray()
2202{
Austin Kinross69822602014-08-12 15:51:37 -07002203 // Delete the Images before the TextureStorage.
2204 // Images might be relying on the TextureStorage for some of their data.
2205 // 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 -07002206 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002207 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002208}
2209
Brandon Jones142ec422014-07-16 10:31:30 -07002210Image *TextureD3D_2DArray::getImage(int level, int layer) const
2211{
2212 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2213 ASSERT(layer < mLayerCounts[level]);
2214 return mImageArray[level][layer];
2215}
2216
Jamie Madillfeda4d22014-09-17 13:03:29 -04002217Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2218{
2219 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2220 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2221 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2222 return mImageArray[index.mipIndex][index.layerIndex];
2223}
2224
Brandon Jones142ec422014-07-16 10:31:30 -07002225GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2226{
2227 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2228 return mLayerCounts[level];
2229}
2230
Brandon Jones142ec422014-07-16 10:31:30 -07002231GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2232{
2233 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2234}
2235
2236GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2237{
2238 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2239}
2240
Brandon Jones142ec422014-07-16 10:31:30 -07002241GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2242{
2243 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2244}
2245
2246bool TextureD3D_2DArray::isDepth(GLint level) const
2247{
Geoff Lang5d601382014-07-22 15:14:06 -04002248 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002249}
2250
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002251gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2252 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2253 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002254{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002255 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2256
Geoff Lang5d601382014-07-22 15:14:06 -04002257 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2258
Brandon Jones142ec422014-07-16 10:31:30 -07002259 redefineImage(level, sizedInternalFormat, width, height, depth);
2260
Geoff Lang5d601382014-07-22 15:14:06 -04002261 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2262 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002263
2264 for (int i = 0; i < depth; i++)
2265 {
2266 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002267 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2268 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002269 if (error.isError())
2270 {
2271 return error;
2272 }
Brandon Jones142ec422014-07-16 10:31:30 -07002273 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002274
2275 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002276}
2277
Geoff Langb5348332014-09-02 13:16:34 -04002278gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2279 GLsizei width, GLsizei height, GLsizei depth,
2280 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002281{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002282 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2283
Brandon Jones142ec422014-07-16 10:31:30 -07002284 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2285 redefineImage(level, format, width, height, depth);
2286
Geoff Lang5d601382014-07-22 15:14:06 -04002287 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2288 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002289
2290 for (int i = 0; i < depth; i++)
2291 {
2292 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002293 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2294 if (error.isError())
2295 {
2296 return error;
2297 }
Brandon Jones142ec422014-07-16 10:31:30 -07002298 }
Geoff Langb5348332014-09-02 13:16:34 -04002299
2300 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002301}
2302
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002303gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2304 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2305 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002306{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002307 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2308
Geoff Lang5d601382014-07-22 15:14:06 -04002309 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2310 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002311
2312 for (int i = 0; i < depth; i++)
2313 {
2314 int layer = zoffset + i;
2315 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2316
Jamie Madillfeda4d22014-09-17 13:03:29 -04002317 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002318 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2319 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002320 if (error.isError())
2321 {
2322 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002323 }
2324 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002325
2326 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002327}
2328
Geoff Langb5348332014-09-02 13:16:34 -04002329gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2330 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2331 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002332{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002333 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2334
Geoff Lang5d601382014-07-22 15:14:06 -04002335 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2336 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002337
2338 for (int i = 0; i < depth; i++)
2339 {
2340 int layer = zoffset + i;
2341 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2342
Geoff Langb5348332014-09-02 13:16:34 -04002343 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2344 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002345 {
Geoff Langb5348332014-09-02 13:16:34 -04002346 return error;
2347 }
2348
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002349 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2350 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2351 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002352 if (error.isError())
2353 {
2354 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002355 }
2356 }
Geoff Langb5348332014-09-02 13:16:34 -04002357
2358 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002359}
2360
Geoff Langef7b0162014-09-04 13:29:23 -04002361gl::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 -07002362{
2363 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002364 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002365}
2366
Geoff Langef7b0162014-09-04 13:29:23 -04002367gl::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 -07002368{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002369 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2370
Brandon Jones142ec422014-07-16 10:31:30 -07002371 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2372 // the current level we're copying to is defined (with appropriate format, width & height)
2373 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2374
Jamie Madill82bf0c52014-10-03 11:50:53 -04002375 gl::Rectangle sourceRect(x, y, width, height);
2376
Brandon Jones142ec422014-07-16 10:31:30 -07002377 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2378 {
Geoff Langef7b0162014-09-04 13:29:23 -04002379 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2380 if (error.isError())
2381 {
2382 return error;
2383 }
2384
Brandon Jones142ec422014-07-16 10:31:30 -07002385 mDirtyImages = true;
2386 }
2387 else
2388 {
Geoff Langef7b0162014-09-04 13:29:23 -04002389 gl::Error error = ensureRenderTarget();
2390 if (error.isError())
2391 {
2392 return error;
2393 }
Brandon Jones142ec422014-07-16 10:31:30 -07002394
2395 if (isValidLevel(level))
2396 {
Geoff Langef7b0162014-09-04 13:29:23 -04002397 error = updateStorageLevel(level);
2398 if (error.isError())
2399 {
2400 return error;
2401 }
Brandon Jones142ec422014-07-16 10:31:30 -07002402
Geoff Langef7b0162014-09-04 13:29:23 -04002403 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2404 xoffset, yoffset, zoffset, mTexStorage, level);
2405 if (error.isError())
2406 {
2407 return error;
2408 }
Brandon Jones142ec422014-07-16 10:31:30 -07002409 }
2410 }
Geoff Langef7b0162014-09-04 13:29:23 -04002411 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002412}
2413
Geoff Lang1f8532b2014-09-05 09:46:13 -04002414gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002415{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002416 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2417
Brandon Jones142ec422014-07-16 10:31:30 -07002418 deleteImages();
2419
2420 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2421 {
2422 GLsizei levelWidth = std::max(1, width >> level);
2423 GLsizei levelHeight = std::max(1, height >> level);
2424
2425 mLayerCounts[level] = (level < levels ? depth : 0);
2426
2427 if (mLayerCounts[level] > 0)
2428 {
2429 // Create new images for this level
2430 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2431
2432 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2433 {
2434 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2435 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2436 levelHeight, 1, true);
2437 }
2438 }
2439 }
2440
Geoff Lang1f8532b2014-09-05 09:46:13 -04002441 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002442 bool renderTarget = IsRenderTargetUsage(mUsage);
2443 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002444
2445 gl::Error error = setCompleteTexStorage(storage);
2446 if (error.isError())
2447 {
2448 SafeDelete(storage);
2449 return error;
2450 }
2451
2452 mImmutable = true;
2453
2454 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002455}
2456
Brandon Jones6053a522014-07-25 16:22:09 -07002457void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002458{
Brandon Jones6053a522014-07-25 16:22:09 -07002459 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002460}
2461
Brandon Jones6053a522014-07-25 16:22:09 -07002462void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002463{
Brandon Jones6053a522014-07-25 16:22:09 -07002464 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002465}
2466
Brandon Jones6053a522014-07-25 16:22:09 -07002467
Jamie Madill4aa79e12014-09-29 10:46:14 -04002468void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002469{
2470 int baseWidth = getBaseLevelWidth();
2471 int baseHeight = getBaseLevelHeight();
2472 int baseDepth = getBaseLevelDepth();
2473 GLenum baseFormat = getBaseLevelInternalFormat();
2474
2475 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2476 int levelCount = mipLevels();
2477 for (int level = 1; level < levelCount; level++)
2478 {
2479 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2480 }
Brandon Jones142ec422014-07-16 10:31:30 -07002481}
2482
Jamie Madillac7579c2014-09-17 16:59:33 -04002483unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002484{
Geoff Langef7b0162014-09-04 13:29:23 -04002485 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002486}
2487
Geoff Lang64f23f62014-09-10 14:40:12 -04002488gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002489{
2490 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002491 gl::Error error = ensureRenderTarget();
2492 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002493 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002494 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002495 }
2496
Geoff Langef7b0162014-09-04 13:29:23 -04002497 error = updateStorageLevel(index.mipIndex);
2498 if (error.isError())
2499 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002500 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002501 }
2502
Geoff Lang64f23f62014-09-10 14:40:12 -04002503 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002504}
2505
Geoff Langef7b0162014-09-04 13:29:23 -04002506gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002507{
2508 // Only initialize the first time this texture is used as a render target or shader resource
2509 if (mTexStorage)
2510 {
Geoff Langef7b0162014-09-04 13:29:23 -04002511 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002512 }
2513
2514 // do not attempt to create storage for nonexistant data
2515 if (!isLevelComplete(0))
2516 {
Geoff Langef7b0162014-09-04 13:29:23 -04002517 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002518 }
2519
2520 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2521
Geoff Langef7b0162014-09-04 13:29:23 -04002522 TextureStorage *storage = NULL;
2523 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2524 if (error.isError())
2525 {
2526 return error;
2527 }
2528
2529 error = setCompleteTexStorage(storage);
2530 if (error.isError())
2531 {
2532 SafeDelete(storage);
2533 return error;
2534 }
2535
Brandon Jones142ec422014-07-16 10:31:30 -07002536 ASSERT(mTexStorage);
2537
2538 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002539 error = updateStorage();
2540 if (error.isError())
2541 {
2542 return error;
2543 }
2544
2545 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002546}
2547
Geoff Langef7b0162014-09-04 13:29:23 -04002548gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002549{
2550 GLsizei width = getBaseLevelWidth();
2551 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002552 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002553 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002554
2555 ASSERT(width > 0 && height > 0 && depth > 0);
2556
2557 // use existing storage level count, when previously specified by TexStorage*D
2558 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2559
Geoff Langef7b0162014-09-04 13:29:23 -04002560 // TODO(geofflang): Verify storage creation succeeds
2561 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2562
2563 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002564}
2565
Geoff Langef7b0162014-09-04 13:29:23 -04002566gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002567{
2568 SafeDelete(mTexStorage);
2569 mTexStorage = newCompleteTexStorage;
2570 mDirtyImages = true;
2571
2572 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2573 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002574
2575 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002576}
2577
Geoff Langef7b0162014-09-04 13:29:23 -04002578gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002579{
2580 ASSERT(mTexStorage != NULL);
2581 GLint storageLevels = mTexStorage->getLevelCount();
2582 for (int level = 0; level < storageLevels; level++)
2583 {
2584 if (isLevelComplete(level))
2585 {
Geoff Langef7b0162014-09-04 13:29:23 -04002586 gl::Error error = updateStorageLevel(level);
2587 if (error.isError())
2588 {
2589 return error;
2590 }
Brandon Jones142ec422014-07-16 10:31:30 -07002591 }
2592 }
Geoff Langef7b0162014-09-04 13:29:23 -04002593
2594 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002595}
2596
Brandon Jones142ec422014-07-16 10:31:30 -07002597bool TextureD3D_2DArray::isValidLevel(int level) const
2598{
2599 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2600}
2601
2602bool TextureD3D_2DArray::isLevelComplete(int level) const
2603{
2604 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2605
2606 if (isImmutable())
2607 {
2608 return true;
2609 }
2610
2611 GLsizei width = getBaseLevelWidth();
2612 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002613 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002614
2615 if (width <= 0 || height <= 0 || layers <= 0)
2616 {
2617 return false;
2618 }
2619
2620 if (level == 0)
2621 {
2622 return true;
2623 }
2624
2625 if (getInternalFormat(level) != getInternalFormat(0))
2626 {
2627 return false;
2628 }
2629
2630 if (getWidth(level) != std::max(1, width >> level))
2631 {
2632 return false;
2633 }
2634
2635 if (getHeight(level) != std::max(1, height >> level))
2636 {
2637 return false;
2638 }
2639
Jamie Madill3269bcb2014-09-30 16:33:52 -04002640 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002641 {
2642 return false;
2643 }
2644
2645 return true;
2646}
2647
Geoff Langef7b0162014-09-04 13:29:23 -04002648gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002649{
2650 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2651 ASSERT(isLevelComplete(level));
2652
2653 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2654 {
2655 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2656 if (mImageArray[level][layer]->isDirty())
2657 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002658 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2659 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002660 gl::Error error = commitRegion(index, region);
2661 if (error.isError())
2662 {
2663 return error;
2664 }
Brandon Jones142ec422014-07-16 10:31:30 -07002665 }
2666 }
Geoff Langef7b0162014-09-04 13:29:23 -04002667
2668 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002669}
2670
2671void TextureD3D_2DArray::deleteImages()
2672{
2673 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2674 {
2675 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2676 {
2677 delete mImageArray[level][layer];
2678 }
2679 delete[] mImageArray[level];
2680 mImageArray[level] = NULL;
2681 mLayerCounts[level] = 0;
2682 }
2683}
2684
2685void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2686{
2687 // If there currently is a corresponding storage texture image, it has these parameters
2688 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2689 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002690 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002691 const GLenum storageFormat = getBaseLevelInternalFormat();
2692
2693 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2694 {
2695 delete mImageArray[level][layer];
2696 }
2697 delete[] mImageArray[level];
2698 mImageArray[level] = NULL;
2699 mLayerCounts[level] = depth;
2700
2701 if (depth > 0)
2702 {
2703 mImageArray[level] = new ImageD3D*[depth]();
2704
2705 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2706 {
2707 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2708 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2709 }
2710 }
2711
2712 if (mTexStorage)
2713 {
2714 const int storageLevels = mTexStorage->getLevelCount();
2715
2716 if ((level >= storageLevels && storageLevels != 0) ||
2717 width != storageWidth ||
2718 height != storageHeight ||
2719 depth != storageDepth ||
2720 internalformat != storageFormat) // Discard mismatched storage
2721 {
2722 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2723 {
2724 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2725 {
2726 mImageArray[level][layer]->markDirty();
2727 }
2728 }
2729
2730 delete mTexStorage;
2731 mTexStorage = NULL;
2732 mDirtyImages = true;
2733 }
2734 }
2735}
2736
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002737gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002738{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002739 ASSERT(index.hasLayer());
2740 GLint level = index.mipIndex;
2741 GLint layerTarget = index.layerIndex;
2742
Jamie Madill3269bcb2014-09-30 16:33:52 -04002743 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002744 {
2745 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill433bfd32014-10-20 12:07:36 -04002746 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002747 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002748 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002749 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002750 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002751
2752 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002753 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002754
2755 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002756}
2757
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002758gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2759{
2760 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2761}
2762
Jamie Madillcb83dc12014-09-29 10:46:12 -04002763gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2764{
2765 return gl::ImageIndex::Make2DArray(mip, layer);
2766}
2767
Brandon Jones78b1acd2014-07-15 15:33:07 -07002768}