blob: bbe1261f5b968bdc8a4c42c2f6681fa5e4eafb81 [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
Jamie Madille76bdda2014-10-20 17:13:52 -0400434bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
435{
436 rx::Image *image = getImage(index);
437 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
438 return (image->isRenderableFormat() && levelsComplete);
439}
440
Jamie Madill710e5772014-10-20 17:13:53 -0400441gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
442{
443 if (mTexStorage)
444 {
445 ASSERT(isValidIndex(index));
446 Image *image = getImage(index);
447 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
448 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
449 if (error.isError())
450 {
451 return error;
452 }
453
454 image->markClean();
455 }
456
457 return gl::Error(GL_NO_ERROR);
458}
459
Brandon Jones78b1acd2014-07-15 15:33:07 -0700460TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400461 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700462{
463 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
464 {
465 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
466 }
467}
468
469TextureD3D_2D::~TextureD3D_2D()
470{
Austin Kinross69822602014-08-12 15:51:37 -0700471 // Delete the Images before the TextureStorage.
472 // Images might be relying on the TextureStorage for some of their data.
473 // 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 -0700474 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
475 {
476 delete mImageArray[i];
477 }
Austin Kinross69822602014-08-12 15:51:37 -0700478
479 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700480}
481
Brandon Jonescef06ff2014-08-05 13:27:48 -0700482Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700483{
484 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700485 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700486 return mImageArray[level];
487}
488
Jamie Madillfeda4d22014-09-17 13:03:29 -0400489Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
490{
491 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400492 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400493 ASSERT(index.type == GL_TEXTURE_2D);
494 return mImageArray[index.mipIndex];
495}
496
Brandon Jonescef06ff2014-08-05 13:27:48 -0700497GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700498{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700499 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
500 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700501}
502
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503GLsizei TextureD3D_2D::getWidth(GLint level) const
504{
505 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
506 return mImageArray[level]->getWidth();
507 else
508 return 0;
509}
510
511GLsizei TextureD3D_2D::getHeight(GLint level) const
512{
513 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
514 return mImageArray[level]->getHeight();
515 else
516 return 0;
517}
518
519GLenum TextureD3D_2D::getInternalFormat(GLint level) const
520{
521 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
522 return mImageArray[level]->getInternalFormat();
523 else
524 return GL_NONE;
525}
526
527GLenum TextureD3D_2D::getActualFormat(GLint level) const
528{
529 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
530 return mImageArray[level]->getActualFormat();
531 else
532 return GL_NONE;
533}
534
535bool TextureD3D_2D::isDepth(GLint level) const
536{
Geoff Lang5d601382014-07-22 15:14:06 -0400537 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538}
539
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400540gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
541 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
542 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700544 ASSERT(target == GL_TEXTURE_2D && depth == 1);
545
Geoff Lang5d601382014-07-22 15:14:06 -0400546 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
547
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700548 bool fastUnpacked = false;
549
Brandon Jonescef06ff2014-08-05 13:27:48 -0700550 redefineImage(level, sizedInternalFormat, width, height);
551
Jamie Madillba6bc952014-10-06 10:56:22 -0400552 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
553
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700554 // Attempt a fast gpu copy of the pixel data to the surface
555 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
556 {
557 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400558 RenderTarget *destRenderTarget = NULL;
559 gl::Error error = getRenderTarget(index, &destRenderTarget);
560 if (error.isError())
561 {
562 return error;
563 }
564
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700565 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
566
Geoff Lang64f23f62014-09-10 14:40:12 -0400567 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
568 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700569 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400570 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700571 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400572
573 // Ensure we don't overwrite our newly initialized data
574 mImageArray[level]->markClean();
575
576 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700577 }
578
579 if (!fastUnpacked)
580 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400581 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400582 if (error.isError())
583 {
584 return error;
585 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400587
588 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700589}
590
Geoff Langb5348332014-09-02 13:16:34 -0400591gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
592 GLsizei width, GLsizei height, GLsizei depth,
593 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700594{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700595 ASSERT(target == GL_TEXTURE_2D && depth == 1);
596
597 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
598 redefineImage(level, format, width, height);
599
Geoff Langb5348332014-09-02 13:16:34 -0400600 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700601}
602
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400603gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
604 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
605 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700607 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
608
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700609 bool fastUnpacked = false;
610
Jamie Madillac7579c2014-09-17 16:59:33 -0400611 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400612 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
614 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400615 RenderTarget *renderTarget = NULL;
616 gl::Error error = getRenderTarget(index, &renderTarget);
617 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700618 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400619 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700620 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400621
622 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
623 if (error.isError())
624 {
625 return error;
626 }
627
628 // Ensure we don't overwrite our newly initialized data
629 mImageArray[level]->markClean();
630
631 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632 }
633
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400634 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400636 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
637 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400639
640 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700641}
642
Geoff Langb5348332014-09-02 13:16:34 -0400643gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
644 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
645 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700646{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700647 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
648
Geoff Langb5348332014-09-02 13:16:34 -0400649 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
650 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651 {
Geoff Langb5348332014-09-02 13:16:34 -0400652 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700653 }
Geoff Langb5348332014-09-02 13:16:34 -0400654
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400655 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
656 gl::Box region(xoffset, yoffset, 0, width, height, 1);
657 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700658}
659
Geoff Langef7b0162014-09-04 13:29:23 -0400660gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
661 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700663 ASSERT(target == GL_TEXTURE_2D);
664
665 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
666 redefineImage(level, sizedInternalFormat, width, height);
667
Jamie Madill82bf0c52014-10-03 11:50:53 -0400668 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400669 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400670
Jamie Madille76bdda2014-10-20 17:13:52 -0400671 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672 {
Geoff Langef7b0162014-09-04 13:29:23 -0400673 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
674 if (error.isError())
675 {
676 return error;
677 }
678
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679 mDirtyImages = true;
680 }
681 else
682 {
Geoff Langef7b0162014-09-04 13:29:23 -0400683 gl::Error error = ensureRenderTarget();
684 if (error.isError())
685 {
686 return error;
687 }
688
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700689 mImageArray[level]->markClean();
690
691 if (width != 0 && height != 0 && isValidLevel(level))
692 {
Geoff Langef7b0162014-09-04 13:29:23 -0400693 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
694 if (error.isError())
695 {
696 return error;
697 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700698 }
699 }
Geoff Langef7b0162014-09-04 13:29:23 -0400700
701 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700702}
703
Geoff Langef7b0162014-09-04 13:29:23 -0400704gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
705 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700706{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700707 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
708
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700709 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
710 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700711
Jamie Madill82bf0c52014-10-03 11:50:53 -0400712 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400713 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400714
Jamie Madille76bdda2014-10-20 17:13:52 -0400715 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700716 {
Geoff Langef7b0162014-09-04 13:29:23 -0400717 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
718 if (error.isError())
719 {
720 return error;
721 }
722
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700723 mDirtyImages = true;
724 }
725 else
726 {
Geoff Langef7b0162014-09-04 13:29:23 -0400727 gl::Error error = ensureRenderTarget();
728 if (error.isError())
729 {
730 return error;
731 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700732
733 if (isValidLevel(level))
734 {
Geoff Langef7b0162014-09-04 13:29:23 -0400735 error = updateStorageLevel(level);
736 if (error.isError())
737 {
738 return error;
739 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700740
Geoff Langef7b0162014-09-04 13:29:23 -0400741 error = mRenderer->copyImage2D(source, sourceRect,
742 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
743 xoffset, yoffset, mTexStorage, level);
744 if (error.isError())
745 {
746 return error;
747 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700748 }
749 }
Geoff Langef7b0162014-09-04 13:29:23 -0400750
751 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700752}
753
Geoff Lang1f8532b2014-09-05 09:46:13 -0400754gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700755{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700756 ASSERT(target == GL_TEXTURE_2D && depth == 1);
757
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700758 for (int level = 0; level < levels; level++)
759 {
760 GLsizei levelWidth = std::max(1, width >> level);
761 GLsizei levelHeight = std::max(1, height >> level);
762 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
763 }
764
765 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
766 {
767 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
768 }
769
Geoff Lang1f8532b2014-09-05 09:46:13 -0400770 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400771 bool renderTarget = IsRenderTargetUsage(mUsage);
772 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400773
774 gl::Error error = setCompleteTexStorage(storage);
775 if (error.isError())
776 {
777 SafeDelete(storage);
778 return error;
779 }
780
781 mImmutable = true;
782
783 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700784}
785
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700786void TextureD3D_2D::bindTexImage(egl::Surface *surface)
787{
788 GLenum internalformat = surface->getFormat();
789
790 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
791
792 if (mTexStorage)
793 {
794 SafeDelete(mTexStorage);
795 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400796
797 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700798
799 mDirtyImages = true;
800}
801
802void TextureD3D_2D::releaseTexImage()
803{
804 if (mTexStorage)
805 {
806 SafeDelete(mTexStorage);
807 }
808
809 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
810 {
811 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
812 }
813}
814
Jamie Madill4aa79e12014-09-29 10:46:14 -0400815void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700816{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700819 for (int level = 1; level < levelCount; level++)
820 {
821 redefineImage(level, getBaseLevelInternalFormat(),
822 std::max(getBaseLevelWidth() >> level, 1),
823 std::max(getBaseLevelHeight() >> level, 1));
824 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700825}
826
Jamie Madillac7579c2014-09-17 16:59:33 -0400827unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700828{
Jamie Madillac7579c2014-09-17 16:59:33 -0400829 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400830 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700831}
832
Geoff Lang64f23f62014-09-10 14:40:12 -0400833gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700834{
Jamie Madillac7579c2014-09-17 16:59:33 -0400835 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700836
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700837 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400838 gl::Error error = ensureRenderTarget();
839 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700840 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400841 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700842 }
843
Geoff Langef7b0162014-09-04 13:29:23 -0400844 error = updateStorageLevel(index.mipIndex);
845 if (error.isError())
846 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400847 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400848 }
849
Geoff Lang64f23f62014-09-10 14:40:12 -0400850 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700851}
852
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700853bool TextureD3D_2D::isValidLevel(int level) const
854{
855 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
856}
857
858bool TextureD3D_2D::isLevelComplete(int level) const
859{
860 if (isImmutable())
861 {
862 return true;
863 }
864
Brandon Jones78b1acd2014-07-15 15:33:07 -0700865 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866
867 GLsizei width = baseImage->getWidth();
868 GLsizei height = baseImage->getHeight();
869
870 if (width <= 0 || height <= 0)
871 {
872 return false;
873 }
874
875 // The base image level is complete if the width and height are positive
876 if (level == 0)
877 {
878 return true;
879 }
880
881 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700882 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700883
884 if (image->getInternalFormat() != baseImage->getInternalFormat())
885 {
886 return false;
887 }
888
889 if (image->getWidth() != std::max(1, width >> level))
890 {
891 return false;
892 }
893
894 if (image->getHeight() != std::max(1, height >> level))
895 {
896 return false;
897 }
898
899 return true;
900}
901
Jamie Madille76bdda2014-10-20 17:13:52 -0400902bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
903{
904 return isLevelComplete(index.mipIndex);
905}
906
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700907// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400908gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700909{
910 // Only initialize the first time this texture is used as a render target or shader resource
911 if (mTexStorage)
912 {
Geoff Langef7b0162014-09-04 13:29:23 -0400913 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700914 }
915
916 // do not attempt to create storage for nonexistant data
917 if (!isLevelComplete(0))
918 {
Geoff Langef7b0162014-09-04 13:29:23 -0400919 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700920 }
921
922 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
923
Geoff Langef7b0162014-09-04 13:29:23 -0400924 TextureStorage *storage = NULL;
925 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
926 if (error.isError())
927 {
928 return error;
929 }
930
931 error = setCompleteTexStorage(storage);
932 if (error.isError())
933 {
934 SafeDelete(storage);
935 return error;
936 }
937
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700938 ASSERT(mTexStorage);
939
940 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400941 error = updateStorage();
942 if (error.isError())
943 {
944 return error;
945 }
946
947 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700948}
949
Geoff Langef7b0162014-09-04 13:29:23 -0400950gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700951{
952 GLsizei width = getBaseLevelWidth();
953 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400954 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700955
956 ASSERT(width > 0 && height > 0);
957
958 // use existing storage level count, when previously specified by TexStorage*D
959 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
960
Geoff Langef7b0162014-09-04 13:29:23 -0400961 // TODO(geofflang): Determine if the texture creation succeeded
962 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
963
964 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700965}
966
Geoff Langef7b0162014-09-04 13:29:23 -0400967gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700968{
Geoff Langef7b0162014-09-04 13:29:23 -0400969 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700970 {
Geoff Langef7b0162014-09-04 13:29:23 -0400971 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700972 {
Geoff Langef7b0162014-09-04 13:29:23 -0400973 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
974 if (error.isError())
975 {
976 return error;
977 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700978 }
979 }
980
Geoff Langef7b0162014-09-04 13:29:23 -0400981 SafeDelete(mTexStorage);
982 mTexStorage = newCompleteTexStorage;
983
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700984 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400985
986 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700987}
988
Geoff Langef7b0162014-09-04 13:29:23 -0400989gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990{
991 ASSERT(mTexStorage != NULL);
992 GLint storageLevels = mTexStorage->getLevelCount();
993 for (int level = 0; level < storageLevels; level++)
994 {
995 if (mImageArray[level]->isDirty() && isLevelComplete(level))
996 {
Geoff Langef7b0162014-09-04 13:29:23 -0400997 gl::Error error = updateStorageLevel(level);
998 if (error.isError())
999 {
1000 return error;
1001 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001002 }
1003 }
Geoff Langef7b0162014-09-04 13:29:23 -04001004
1005 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001006}
1007
Geoff Langef7b0162014-09-04 13:29:23 -04001008gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001009{
1010 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1011 ASSERT(isLevelComplete(level));
1012
1013 if (mImageArray[level]->isDirty())
1014 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001015 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1016 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001017 gl::Error error = commitRegion(index, region);
1018 if (error.isError())
1019 {
1020 return error;
1021 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001022 }
Geoff Langef7b0162014-09-04 13:29:23 -04001023
1024 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001025}
1026
1027void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1028{
1029 // If there currently is a corresponding storage texture image, it has these parameters
1030 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1031 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1032 const GLenum storageFormat = getBaseLevelInternalFormat();
1033
1034 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1035
1036 if (mTexStorage)
1037 {
1038 const int storageLevels = mTexStorage->getLevelCount();
1039
1040 if ((level >= storageLevels && storageLevels != 0) ||
1041 width != storageWidth ||
1042 height != storageHeight ||
1043 internalformat != storageFormat) // Discard mismatched storage
1044 {
1045 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1046 {
1047 mImageArray[i]->markDirty();
1048 }
1049
1050 SafeDelete(mTexStorage);
1051 mDirtyImages = true;
1052 }
1053 }
1054}
1055
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001056gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1057{
1058 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1059}
Brandon Jones0511e802014-07-14 16:27:26 -07001060
Jamie Madillcb83dc12014-09-29 10:46:12 -04001061gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1062{
1063 // "layer" does not apply to 2D Textures.
1064 return gl::ImageIndex::Make2D(mip);
1065}
1066
Jamie Madill710e5772014-10-20 17:13:53 -04001067bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1068{
1069 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1070 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1071}
1072
Brandon Jones78b1acd2014-07-15 15:33:07 -07001073TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001074 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001075{
1076 for (int i = 0; i < 6; i++)
1077 {
1078 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1079 {
1080 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1081 }
1082 }
1083}
1084
1085TextureD3D_Cube::~TextureD3D_Cube()
1086{
Austin Kinross69822602014-08-12 15:51:37 -07001087 // Delete the Images before the TextureStorage.
1088 // Images might be relying on the TextureStorage for some of their data.
1089 // 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 -07001090 for (int i = 0; i < 6; i++)
1091 {
1092 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1093 {
1094 SafeDelete(mImageArray[i][j]);
1095 }
1096 }
Austin Kinross69822602014-08-12 15:51:37 -07001097
1098 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001099}
1100
Brandon Jonescef06ff2014-08-05 13:27:48 -07001101Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001102{
1103 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001104 ASSERT(layer < 6);
1105 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001106}
1107
Jamie Madillfeda4d22014-09-17 13:03:29 -04001108Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1109{
1110 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1111 ASSERT(index.layerIndex < 6);
1112 return mImageArray[index.layerIndex][index.mipIndex];
1113}
1114
Brandon Jonescef06ff2014-08-05 13:27:48 -07001115GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001116{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001117 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1118 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001119}
1120
Brandon Jonescef06ff2014-08-05 13:27:48 -07001121GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001122{
1123 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001124 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001125 else
1126 return GL_NONE;
1127}
1128
Brandon Jonescef06ff2014-08-05 13:27:48 -07001129bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001130{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001131 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001132}
1133
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001134gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1135 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1136 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001137{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001138 ASSERT(depth == 1);
1139
Geoff Lang5d601382014-07-22 15:14:06 -04001140 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001141 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001142
Jamie Madillba6bc952014-10-06 10:56:22 -04001143 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001144
Jamie Madillba6bc952014-10-06 10:56:22 -04001145 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001146}
1147
Geoff Langb5348332014-09-02 13:16:34 -04001148gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1149 GLsizei width, GLsizei height, GLsizei depth,
1150 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001151{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001152 ASSERT(depth == 1);
1153
Brandon Jones0511e802014-07-14 16:27:26 -07001154 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001155 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1156
Brandon Jones0511e802014-07-14 16:27:26 -07001157 redefineImage(faceIndex, level, format, width, height);
1158
Geoff Langb5348332014-09-02 13:16:34 -04001159 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001160}
1161
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001162gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1163 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1164 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001165{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001166 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001167 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001168 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001169}
1170
Geoff Langb5348332014-09-02 13:16:34 -04001171gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1172 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1173 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001174{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001175 ASSERT(depth == 1 && zoffset == 0);
1176
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001177 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001178
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001179 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 -04001180 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001181 {
Geoff Langb5348332014-09-02 13:16:34 -04001182 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001183 }
Geoff Langb5348332014-09-02 13:16:34 -04001184
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001185 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1186 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001187}
1188
Geoff Langef7b0162014-09-04 13:29:23 -04001189gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1190 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001191{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001192 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001193 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1194
Brandon Jones0511e802014-07-14 16:27:26 -07001195 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1196
Jamie Madill82bf0c52014-10-03 11:50:53 -04001197 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001198 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001199
Jamie Madille76bdda2014-10-20 17:13:52 -04001200 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001201 {
Geoff Langef7b0162014-09-04 13:29:23 -04001202 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1203 if (error.isError())
1204 {
1205 return error;
1206 }
1207
Brandon Jones0511e802014-07-14 16:27:26 -07001208 mDirtyImages = true;
1209 }
1210 else
1211 {
Geoff Langef7b0162014-09-04 13:29:23 -04001212 gl::Error error = ensureRenderTarget();
1213 if (error.isError())
1214 {
1215 return error;
1216 }
1217
Brandon Jones0511e802014-07-14 16:27:26 -07001218 mImageArray[faceIndex][level]->markClean();
1219
1220 ASSERT(width == height);
1221
1222 if (width > 0 && isValidFaceLevel(faceIndex, level))
1223 {
Geoff Langef7b0162014-09-04 13:29:23 -04001224 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1225 if (error.isError())
1226 {
1227 return error;
1228 }
Brandon Jones0511e802014-07-14 16:27:26 -07001229 }
1230 }
Geoff Langef7b0162014-09-04 13:29:23 -04001231
1232 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001233}
1234
Geoff Langef7b0162014-09-04 13:29:23 -04001235gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1236 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001237{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001238 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001239
Jamie Madill82bf0c52014-10-03 11:50:53 -04001240 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001241 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001242
Jamie Madille76bdda2014-10-20 17:13:52 -04001243 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001244 {
Geoff Langef7b0162014-09-04 13:29:23 -04001245 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1246 if (error.isError())
1247 {
1248 return error;
1249 }
1250
Brandon Jones0511e802014-07-14 16:27:26 -07001251 mDirtyImages = true;
1252 }
1253 else
1254 {
Geoff Langef7b0162014-09-04 13:29:23 -04001255 gl::Error error = ensureRenderTarget();
1256 if (error.isError())
1257 {
1258 return error;
1259 }
Brandon Jones0511e802014-07-14 16:27:26 -07001260
1261 if (isValidFaceLevel(faceIndex, level))
1262 {
Geoff Langef7b0162014-09-04 13:29:23 -04001263 error = updateStorageFaceLevel(faceIndex, level);
1264 if (error.isError())
1265 {
1266 return error;
1267 }
Brandon Jones0511e802014-07-14 16:27:26 -07001268
Geoff Langef7b0162014-09-04 13:29:23 -04001269 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1270 xoffset, yoffset, mTexStorage, target, level);
1271 if (error.isError())
1272 {
1273 return error;
1274 }
Brandon Jones0511e802014-07-14 16:27:26 -07001275 }
1276 }
Geoff Langef7b0162014-09-04 13:29:23 -04001277
1278 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001279}
1280
Geoff Lang1f8532b2014-09-05 09:46:13 -04001281gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001282{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001283 ASSERT(width == height);
1284 ASSERT(depth == 1);
1285
Brandon Jones0511e802014-07-14 16:27:26 -07001286 for (int level = 0; level < levels; level++)
1287 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001288 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001289 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1290 {
1291 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1292 }
1293 }
1294
1295 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1296 {
1297 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1298 {
1299 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1300 }
1301 }
1302
Geoff Lang1f8532b2014-09-05 09:46:13 -04001303 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001304 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001305 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001306
1307 gl::Error error = setCompleteTexStorage(storage);
1308 if (error.isError())
1309 {
1310 SafeDelete(storage);
1311 return error;
1312 }
1313
1314 mImmutable = true;
1315
1316 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001317}
1318
Brandon Jones0511e802014-07-14 16:27:26 -07001319// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1320bool TextureD3D_Cube::isCubeComplete() const
1321{
1322 int baseWidth = getBaseLevelWidth();
1323 int baseHeight = getBaseLevelHeight();
1324 GLenum baseFormat = getBaseLevelInternalFormat();
1325
1326 if (baseWidth <= 0 || baseWidth != baseHeight)
1327 {
1328 return false;
1329 }
1330
1331 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1332 {
1333 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1334
1335 if (faceBaseImage.getWidth() != baseWidth ||
1336 faceBaseImage.getHeight() != baseHeight ||
1337 faceBaseImage.getInternalFormat() != baseFormat )
1338 {
1339 return false;
1340 }
1341 }
1342
1343 return true;
1344}
1345
Brandon Jones6053a522014-07-25 16:22:09 -07001346void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1347{
1348 UNREACHABLE();
1349}
1350
1351void TextureD3D_Cube::releaseTexImage()
1352{
1353 UNREACHABLE();
1354}
1355
1356
Jamie Madill4aa79e12014-09-29 10:46:14 -04001357void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001358{
1359 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1360 int levelCount = mipLevels();
1361 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1362 {
1363 for (int level = 1; level < levelCount; level++)
1364 {
1365 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1366 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1367 }
1368 }
Brandon Jones0511e802014-07-14 16:27:26 -07001369}
1370
Jamie Madillac7579c2014-09-17 16:59:33 -04001371unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001372{
Geoff Langef7b0162014-09-04 13:29:23 -04001373 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001374}
1375
Geoff Lang64f23f62014-09-10 14:40:12 -04001376gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001377{
Jamie Madillac7579c2014-09-17 16:59:33 -04001378 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001379
1380 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001381 gl::Error error = ensureRenderTarget();
1382 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001383 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001384 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001385 }
1386
Geoff Langef7b0162014-09-04 13:29:23 -04001387 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1388 if (error.isError())
1389 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001390 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001391 }
1392
Geoff Lang64f23f62014-09-10 14:40:12 -04001393 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001394}
1395
Geoff Langef7b0162014-09-04 13:29:23 -04001396gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001397{
1398 // Only initialize the first time this texture is used as a render target or shader resource
1399 if (mTexStorage)
1400 {
Geoff Langef7b0162014-09-04 13:29:23 -04001401 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001402 }
1403
1404 // do not attempt to create storage for nonexistant data
1405 if (!isFaceLevelComplete(0, 0))
1406 {
Geoff Langef7b0162014-09-04 13:29:23 -04001407 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001408 }
1409
1410 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1411
Geoff Langef7b0162014-09-04 13:29:23 -04001412 TextureStorage *storage = NULL;
1413 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1414 if (error.isError())
1415 {
1416 return error;
1417 }
1418
1419 error = setCompleteTexStorage(storage);
1420 if (error.isError())
1421 {
1422 SafeDelete(storage);
1423 return error;
1424 }
1425
Brandon Jones0511e802014-07-14 16:27:26 -07001426 ASSERT(mTexStorage);
1427
1428 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001429 error = updateStorage();
1430 if (error.isError())
1431 {
1432 return error;
1433 }
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::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001439{
1440 GLsizei size = getBaseLevelWidth();
1441
1442 ASSERT(size > 0);
1443
1444 // use existing storage level count, when previously specified by TexStorage*D
1445 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1446
Geoff Langef7b0162014-09-04 13:29:23 -04001447 // TODO (geofflang): detect if storage creation succeeded
1448 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1449
1450 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001451}
1452
Geoff Langef7b0162014-09-04 13:29:23 -04001453gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001454{
Geoff Langef7b0162014-09-04 13:29:23 -04001455 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001456 {
1457 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1458 {
Geoff Langef7b0162014-09-04 13:29:23 -04001459 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001460 {
Geoff Langef7b0162014-09-04 13:29:23 -04001461 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1462 if (error.isError())
1463 {
1464 return error;
1465 }
Brandon Jones0511e802014-07-14 16:27:26 -07001466 }
1467 }
1468 }
1469
Geoff Langef7b0162014-09-04 13:29:23 -04001470 SafeDelete(mTexStorage);
1471 mTexStorage = newCompleteTexStorage;
1472
Brandon Jones0511e802014-07-14 16:27:26 -07001473 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001474 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001475}
1476
Geoff Langef7b0162014-09-04 13:29:23 -04001477gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001478{
1479 ASSERT(mTexStorage != NULL);
1480 GLint storageLevels = mTexStorage->getLevelCount();
1481 for (int face = 0; face < 6; face++)
1482 {
1483 for (int level = 0; level < storageLevels; level++)
1484 {
1485 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1486 {
Geoff Langef7b0162014-09-04 13:29:23 -04001487 gl::Error error = updateStorageFaceLevel(face, level);
1488 if (error.isError())
1489 {
1490 return error;
1491 }
Brandon Jones0511e802014-07-14 16:27:26 -07001492 }
1493 }
1494 }
Geoff Langef7b0162014-09-04 13:29:23 -04001495
1496 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001497}
1498
Brandon Jones0511e802014-07-14 16:27:26 -07001499bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1500{
1501 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1502}
1503
Brandon Jones0511e802014-07-14 16:27:26 -07001504bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1505{
1506 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1507
1508 if (isImmutable())
1509 {
1510 return true;
1511 }
1512
1513 int baseSize = getBaseLevelWidth();
1514
1515 if (baseSize <= 0)
1516 {
1517 return false;
1518 }
1519
1520 // "isCubeComplete" checks for base level completeness and we must call that
1521 // to determine if any face at level 0 is complete. We omit that check here
1522 // to avoid re-checking cube-completeness for every face at level 0.
1523 if (level == 0)
1524 {
1525 return true;
1526 }
1527
1528 // Check that non-zero levels are consistent with the base level.
1529 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1530
1531 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1532 {
1533 return false;
1534 }
1535
1536 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1537 {
1538 return false;
1539 }
1540
1541 return true;
1542}
1543
Jamie Madille76bdda2014-10-20 17:13:52 -04001544bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1545{
1546 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1547}
1548
Geoff Langef7b0162014-09-04 13:29:23 -04001549gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001550{
1551 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1552 ImageD3D *image = mImageArray[faceIndex][level];
1553
1554 if (image->isDirty())
1555 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001556 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1557 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1558 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001559 gl::Error error = commitRegion(index, region);
1560 if (error.isError())
1561 {
1562 return error;
1563 }
Brandon Jones0511e802014-07-14 16:27:26 -07001564 }
Geoff Langef7b0162014-09-04 13:29:23 -04001565
1566 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001567}
1568
1569void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1570{
1571 // If there currently is a corresponding storage texture image, it has these parameters
1572 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1573 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1574 const GLenum storageFormat = getBaseLevelInternalFormat();
1575
1576 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1577
1578 if (mTexStorage)
1579 {
1580 const int storageLevels = mTexStorage->getLevelCount();
1581
1582 if ((level >= storageLevels && storageLevels != 0) ||
1583 width != storageWidth ||
1584 height != storageHeight ||
1585 internalformat != storageFormat) // Discard mismatched storage
1586 {
1587 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1588 {
1589 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1590 {
1591 mImageArray[faceIndex][level]->markDirty();
1592 }
1593 }
1594
1595 SafeDelete(mTexStorage);
1596
1597 mDirtyImages = true;
1598 }
1599 }
1600}
1601
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001602gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1603{
1604 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1605}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001606
Jamie Madillcb83dc12014-09-29 10:46:12 -04001607gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1608{
1609 // The "layer" of the image index corresponds to the cube face
1610 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1611}
1612
Jamie Madill710e5772014-10-20 17:13:53 -04001613bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1614{
1615 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1616 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1617}
1618
Brandon Jones78b1acd2014-07-15 15:33:07 -07001619TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001620 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001621{
1622 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1623 {
1624 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1625 }
1626}
1627
1628TextureD3D_3D::~TextureD3D_3D()
1629{
Austin Kinross69822602014-08-12 15:51:37 -07001630 // Delete the Images before the TextureStorage.
1631 // Images might be relying on the TextureStorage for some of their data.
1632 // 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 -07001633 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1634 {
1635 delete mImageArray[i];
1636 }
Austin Kinross69822602014-08-12 15:51:37 -07001637
1638 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639}
1640
Brandon Jonescef06ff2014-08-05 13:27:48 -07001641Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001642{
1643 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001644 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001645 return mImageArray[level];
1646}
1647
Jamie Madillfeda4d22014-09-17 13:03:29 -04001648Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1649{
1650 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001651 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001652 ASSERT(index.type == GL_TEXTURE_3D);
1653 return mImageArray[index.mipIndex];
1654}
1655
Brandon Jonescef06ff2014-08-05 13:27:48 -07001656GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001658 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1659 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001660}
1661
Brandon Jones78b1acd2014-07-15 15:33:07 -07001662GLsizei TextureD3D_3D::getWidth(GLint level) const
1663{
1664 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1665 return mImageArray[level]->getWidth();
1666 else
1667 return 0;
1668}
1669
1670GLsizei TextureD3D_3D::getHeight(GLint level) const
1671{
1672 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1673 return mImageArray[level]->getHeight();
1674 else
1675 return 0;
1676}
1677
1678GLsizei TextureD3D_3D::getDepth(GLint level) const
1679{
1680 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1681 return mImageArray[level]->getDepth();
1682 else
1683 return 0;
1684}
1685
1686GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1687{
1688 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1689 return mImageArray[level]->getInternalFormat();
1690 else
1691 return GL_NONE;
1692}
1693
1694bool TextureD3D_3D::isDepth(GLint level) const
1695{
Geoff Lang5d601382014-07-22 15:14:06 -04001696 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697}
1698
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001699gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1700 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1701 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001702{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001703 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001704 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1705
Brandon Jones78b1acd2014-07-15 15:33:07 -07001706 redefineImage(level, sizedInternalFormat, width, height, depth);
1707
1708 bool fastUnpacked = false;
1709
Jamie Madillba6bc952014-10-06 10:56:22 -04001710 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1711
Brandon Jones78b1acd2014-07-15 15:33:07 -07001712 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1713 if (isFastUnpackable(unpack, sizedInternalFormat))
1714 {
1715 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001716 RenderTarget *destRenderTarget = NULL;
1717 gl::Error error = getRenderTarget(index, &destRenderTarget);
1718 if (error.isError())
1719 {
1720 return error;
1721 }
1722
Brandon Jones78b1acd2014-07-15 15:33:07 -07001723 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1724
Geoff Lang64f23f62014-09-10 14:40:12 -04001725 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1726 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001727 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001728 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001729 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001730
1731 // Ensure we don't overwrite our newly initialized data
1732 mImageArray[level]->markClean();
1733
1734 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001735 }
1736
1737 if (!fastUnpacked)
1738 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001739 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001740 if (error.isError())
1741 {
1742 return error;
1743 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001744 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001745
1746 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001747}
1748
Geoff Langb5348332014-09-02 13:16:34 -04001749gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1750 GLsizei width, GLsizei height,GLsizei depth,
1751 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001752{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001753 ASSERT(target == GL_TEXTURE_3D);
1754
Brandon Jones78b1acd2014-07-15 15:33:07 -07001755 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1756 redefineImage(level, format, width, height, depth);
1757
Geoff Langb5348332014-09-02 13:16:34 -04001758 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001759}
1760
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001761gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1762 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1763 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001764{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001765 ASSERT(target == GL_TEXTURE_3D);
1766
Brandon Jones78b1acd2014-07-15 15:33:07 -07001767 bool fastUnpacked = false;
1768
Jamie Madillac7579c2014-09-17 16:59:33 -04001769 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1770
Brandon Jones78b1acd2014-07-15 15:33:07 -07001771 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1772 if (isFastUnpackable(unpack, getInternalFormat(level)))
1773 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001774 RenderTarget *destRenderTarget = NULL;
1775 gl::Error error = getRenderTarget(index, &destRenderTarget);
1776 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001778 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001779 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001780
1781 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1782 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1783 if (error.isError())
1784 {
1785 return error;
1786 }
1787
1788 // Ensure we don't overwrite our newly initialized data
1789 mImageArray[level]->markClean();
1790
1791 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001792 }
1793
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001794 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001795 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001796 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1797 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001798 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001799
1800 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001801}
1802
Geoff Langb5348332014-09-02 13:16:34 -04001803gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1804 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1805 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001807 ASSERT(target == GL_TEXTURE_3D);
1808
Geoff Langb5348332014-09-02 13:16:34 -04001809 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1810 format, imageSize, pixels, mImageArray[level]);
1811 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812 {
Geoff Langb5348332014-09-02 13:16:34 -04001813 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001814 }
Geoff Langb5348332014-09-02 13:16:34 -04001815
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001816 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1817 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1818 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001819}
1820
Geoff Langef7b0162014-09-04 13:29:23 -04001821gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1822 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001823{
1824 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001825 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001826}
1827
Geoff Langef7b0162014-09-04 13:29:23 -04001828gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1829 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001831 ASSERT(target == GL_TEXTURE_3D);
1832
Jamie Madill82bf0c52014-10-03 11:50:53 -04001833 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001834 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001835
Jamie Madille76bdda2014-10-20 17:13:52 -04001836 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001837 {
Geoff Langef7b0162014-09-04 13:29:23 -04001838 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1839 if (error.isError())
1840 {
1841 return error;
1842 }
1843
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844 mDirtyImages = true;
1845 }
1846 else
1847 {
Geoff Langef7b0162014-09-04 13:29:23 -04001848 gl::Error error = ensureRenderTarget();
1849 if (error.isError())
1850 {
1851 return error;
1852 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001853
1854 if (isValidLevel(level))
1855 {
Geoff Langef7b0162014-09-04 13:29:23 -04001856 error = updateStorageLevel(level);
1857 if (error.isError())
1858 {
1859 return error;
1860 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861
Geoff Langef7b0162014-09-04 13:29:23 -04001862 error = mRenderer->copyImage3D(source, sourceRect,
1863 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1864 xoffset, yoffset, zoffset, mTexStorage, level);
1865 if (error.isError())
1866 {
1867 return error;
1868 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001869 }
1870 }
Geoff Langef7b0162014-09-04 13:29:23 -04001871
1872 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001873}
1874
Geoff Lang1f8532b2014-09-05 09:46:13 -04001875gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001876{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001877 ASSERT(target == GL_TEXTURE_3D);
1878
Brandon Jones78b1acd2014-07-15 15:33:07 -07001879 for (int level = 0; level < levels; level++)
1880 {
1881 GLsizei levelWidth = std::max(1, width >> level);
1882 GLsizei levelHeight = std::max(1, height >> level);
1883 GLsizei levelDepth = std::max(1, depth >> level);
1884 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1885 }
1886
1887 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1888 {
1889 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1890 }
1891
Geoff Lang1f8532b2014-09-05 09:46:13 -04001892 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001893 bool renderTarget = IsRenderTargetUsage(mUsage);
1894 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001895
1896 gl::Error error = setCompleteTexStorage(storage);
1897 if (error.isError())
1898 {
1899 SafeDelete(storage);
1900 return error;
1901 }
1902
1903 mImmutable = true;
1904
1905 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001906}
1907
Brandon Jones6053a522014-07-25 16:22:09 -07001908void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909{
Brandon Jones6053a522014-07-25 16:22:09 -07001910 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001911}
1912
Brandon Jones6053a522014-07-25 16:22:09 -07001913void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001914{
Brandon Jones6053a522014-07-25 16:22:09 -07001915 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001916}
1917
Brandon Jones6053a522014-07-25 16:22:09 -07001918
Jamie Madill4aa79e12014-09-29 10:46:14 -04001919void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001920{
1921 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1922 int levelCount = mipLevels();
1923 for (int level = 1; level < levelCount; level++)
1924 {
1925 redefineImage(level, getBaseLevelInternalFormat(),
1926 std::max(getBaseLevelWidth() >> level, 1),
1927 std::max(getBaseLevelHeight() >> level, 1),
1928 std::max(getBaseLevelDepth() >> level, 1));
1929 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001930}
1931
Jamie Madillac7579c2014-09-17 16:59:33 -04001932unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001933{
Geoff Langef7b0162014-09-04 13:29:23 -04001934 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001935}
1936
Geoff Lang64f23f62014-09-10 14:40:12 -04001937gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001938{
1939 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001940 gl::Error error = ensureRenderTarget();
1941 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001942 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001943 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001944 }
1945
Jamie Madillac7579c2014-09-17 16:59:33 -04001946 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001947 {
Geoff Langef7b0162014-09-04 13:29:23 -04001948 error = updateStorage();
1949 if (error.isError())
1950 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001951 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001952 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001953 }
1954 else
1955 {
Geoff Langef7b0162014-09-04 13:29:23 -04001956 error = updateStorageLevel(index.mipIndex);
1957 if (error.isError())
1958 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001959 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001960 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001961 }
1962
Geoff Lang64f23f62014-09-10 14:40:12 -04001963 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001964}
1965
Geoff Langef7b0162014-09-04 13:29:23 -04001966gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001967{
1968 // Only initialize the first time this texture is used as a render target or shader resource
1969 if (mTexStorage)
1970 {
Geoff Langef7b0162014-09-04 13:29:23 -04001971 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001972 }
1973
1974 // do not attempt to create storage for nonexistant data
1975 if (!isLevelComplete(0))
1976 {
Geoff Langef7b0162014-09-04 13:29:23 -04001977 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001978 }
1979
1980 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1981
Geoff Langef7b0162014-09-04 13:29:23 -04001982 rx::TextureStorage *storage = NULL;
1983 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1984 if (error.isError())
1985 {
1986 return error;
1987 }
1988
1989 error = setCompleteTexStorage(storage);
1990 if (error.isError())
1991 {
1992 SafeDelete(storage);
1993 return error;
1994 }
1995
Brandon Jones78b1acd2014-07-15 15:33:07 -07001996 ASSERT(mTexStorage);
1997
1998 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001999 error = updateStorage();
2000 if (error.isError())
2001 {
2002 return error;
2003 }
2004
2005 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002006}
2007
Geoff Langef7b0162014-09-04 13:29:23 -04002008gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002009{
2010 GLsizei width = getBaseLevelWidth();
2011 GLsizei height = getBaseLevelHeight();
2012 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002013 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002014
2015 ASSERT(width > 0 && height > 0 && depth > 0);
2016
2017 // use existing storage level count, when previously specified by TexStorage*D
2018 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2019
Geoff Langef7b0162014-09-04 13:29:23 -04002020 // TODO: Verify creation of the storage succeeded
2021 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2022
2023 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002024}
2025
Geoff Langef7b0162014-09-04 13:29:23 -04002026gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002027{
2028 SafeDelete(mTexStorage);
2029 mTexStorage = newCompleteTexStorage;
2030 mDirtyImages = true;
2031
2032 // We do not support managed 3D storage, as that is D3D9/ES2-only
2033 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002034
2035 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002036}
2037
Geoff Langef7b0162014-09-04 13:29:23 -04002038gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002039{
2040 ASSERT(mTexStorage != NULL);
2041 GLint storageLevels = mTexStorage->getLevelCount();
2042 for (int level = 0; level < storageLevels; level++)
2043 {
2044 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2045 {
Geoff Langef7b0162014-09-04 13:29:23 -04002046 gl::Error error = updateStorageLevel(level);
2047 if (error.isError())
2048 {
2049 return error;
2050 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002051 }
2052 }
Geoff Langef7b0162014-09-04 13:29:23 -04002053
2054 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002055}
2056
Brandon Jones78b1acd2014-07-15 15:33:07 -07002057bool TextureD3D_3D::isValidLevel(int level) const
2058{
2059 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2060}
2061
2062bool TextureD3D_3D::isLevelComplete(int level) const
2063{
2064 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2065
2066 if (isImmutable())
2067 {
2068 return true;
2069 }
2070
2071 GLsizei width = getBaseLevelWidth();
2072 GLsizei height = getBaseLevelHeight();
2073 GLsizei depth = getBaseLevelDepth();
2074
2075 if (width <= 0 || height <= 0 || depth <= 0)
2076 {
2077 return false;
2078 }
2079
2080 if (level == 0)
2081 {
2082 return true;
2083 }
2084
2085 ImageD3D *levelImage = mImageArray[level];
2086
2087 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2088 {
2089 return false;
2090 }
2091
2092 if (levelImage->getWidth() != std::max(1, width >> level))
2093 {
2094 return false;
2095 }
2096
2097 if (levelImage->getHeight() != std::max(1, height >> level))
2098 {
2099 return false;
2100 }
2101
2102 if (levelImage->getDepth() != std::max(1, depth >> level))
2103 {
2104 return false;
2105 }
2106
2107 return true;
2108}
2109
Jamie Madille76bdda2014-10-20 17:13:52 -04002110bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2111{
2112 return isLevelComplete(index.mipIndex);
2113}
2114
Geoff Langef7b0162014-09-04 13:29:23 -04002115gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002116{
2117 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2118 ASSERT(isLevelComplete(level));
2119
2120 if (mImageArray[level]->isDirty())
2121 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002122 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2123 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002124 gl::Error error = commitRegion(index, region);
2125 if (error.isError())
2126 {
2127 return error;
2128 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002129 }
Geoff Langef7b0162014-09-04 13:29:23 -04002130
2131 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002132}
2133
2134void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2135{
2136 // If there currently is a corresponding storage texture image, it has these parameters
2137 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2138 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2139 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2140 const GLenum storageFormat = getBaseLevelInternalFormat();
2141
2142 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2143
2144 if (mTexStorage)
2145 {
2146 const int storageLevels = mTexStorage->getLevelCount();
2147
2148 if ((level >= storageLevels && storageLevels != 0) ||
2149 width != storageWidth ||
2150 height != storageHeight ||
2151 depth != storageDepth ||
2152 internalformat != storageFormat) // Discard mismatched storage
2153 {
2154 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2155 {
2156 mImageArray[i]->markDirty();
2157 }
2158
2159 SafeDelete(mTexStorage);
2160 mDirtyImages = true;
2161 }
2162 }
2163}
2164
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002165gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2166{
2167 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2168 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2169}
Brandon Jones142ec422014-07-16 10:31:30 -07002170
Jamie Madillcb83dc12014-09-29 10:46:12 -04002171gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2172{
2173 // The "layer" here does not apply to 3D images. We use one Image per mip.
2174 return gl::ImageIndex::Make3D(mip);
2175}
2176
Jamie Madill710e5772014-10-20 17:13:53 -04002177bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2178{
2179 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2180 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2181}
2182
Brandon Jones142ec422014-07-16 10:31:30 -07002183TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002184 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002185{
2186 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2187 {
2188 mLayerCounts[level] = 0;
2189 mImageArray[level] = NULL;
2190 }
2191}
2192
2193TextureD3D_2DArray::~TextureD3D_2DArray()
2194{
Austin Kinross69822602014-08-12 15:51:37 -07002195 // Delete the Images before the TextureStorage.
2196 // Images might be relying on the TextureStorage for some of their data.
2197 // 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 -07002198 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002199 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002200}
2201
Brandon Jones142ec422014-07-16 10:31:30 -07002202Image *TextureD3D_2DArray::getImage(int level, int layer) const
2203{
2204 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2205 ASSERT(layer < mLayerCounts[level]);
2206 return mImageArray[level][layer];
2207}
2208
Jamie Madillfeda4d22014-09-17 13:03:29 -04002209Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2210{
2211 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2212 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2213 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2214 return mImageArray[index.mipIndex][index.layerIndex];
2215}
2216
Brandon Jones142ec422014-07-16 10:31:30 -07002217GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2218{
2219 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2220 return mLayerCounts[level];
2221}
2222
Brandon Jones142ec422014-07-16 10:31:30 -07002223GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2224{
2225 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2226}
2227
2228GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2229{
2230 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2231}
2232
Brandon Jones142ec422014-07-16 10:31:30 -07002233GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2234{
2235 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2236}
2237
2238bool TextureD3D_2DArray::isDepth(GLint level) const
2239{
Geoff Lang5d601382014-07-22 15:14:06 -04002240 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002241}
2242
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002243gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2244 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2245 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002246{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002247 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2248
Geoff Lang5d601382014-07-22 15:14:06 -04002249 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2250
Brandon Jones142ec422014-07-16 10:31:30 -07002251 redefineImage(level, sizedInternalFormat, width, height, depth);
2252
Geoff Lang5d601382014-07-22 15:14:06 -04002253 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2254 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002255
2256 for (int i = 0; i < depth; i++)
2257 {
2258 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002259 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2260 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002261 if (error.isError())
2262 {
2263 return error;
2264 }
Brandon Jones142ec422014-07-16 10:31:30 -07002265 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002266
2267 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002268}
2269
Geoff Langb5348332014-09-02 13:16:34 -04002270gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2271 GLsizei width, GLsizei height, GLsizei depth,
2272 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002273{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002274 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2275
Brandon Jones142ec422014-07-16 10:31:30 -07002276 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2277 redefineImage(level, format, width, height, depth);
2278
Geoff Lang5d601382014-07-22 15:14:06 -04002279 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2280 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002281
2282 for (int i = 0; i < depth; i++)
2283 {
2284 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002285 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2286 if (error.isError())
2287 {
2288 return error;
2289 }
Brandon Jones142ec422014-07-16 10:31:30 -07002290 }
Geoff Langb5348332014-09-02 13:16:34 -04002291
2292 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002293}
2294
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002295gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2296 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2297 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002298{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002299 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2300
Geoff Lang5d601382014-07-22 15:14:06 -04002301 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2302 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002303
2304 for (int i = 0; i < depth; i++)
2305 {
2306 int layer = zoffset + i;
2307 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2308
Jamie Madillfeda4d22014-09-17 13:03:29 -04002309 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002310 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2311 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002312 if (error.isError())
2313 {
2314 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002315 }
2316 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002317
2318 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002319}
2320
Geoff Langb5348332014-09-02 13:16:34 -04002321gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2322 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2323 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002324{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002325 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2326
Geoff Lang5d601382014-07-22 15:14:06 -04002327 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2328 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002329
2330 for (int i = 0; i < depth; i++)
2331 {
2332 int layer = zoffset + i;
2333 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2334
Geoff Langb5348332014-09-02 13:16:34 -04002335 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2336 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002337 {
Geoff Langb5348332014-09-02 13:16:34 -04002338 return error;
2339 }
2340
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002341 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2342 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2343 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002344 if (error.isError())
2345 {
2346 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002347 }
2348 }
Geoff Langb5348332014-09-02 13:16:34 -04002349
2350 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002351}
2352
Geoff Langef7b0162014-09-04 13:29:23 -04002353gl::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 -07002354{
2355 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002356 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002357}
2358
Geoff Langef7b0162014-09-04 13:29:23 -04002359gl::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 -07002360{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002361 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2362
Jamie Madill82bf0c52014-10-03 11:50:53 -04002363 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002364 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002365
Jamie Madille76bdda2014-10-20 17:13:52 -04002366 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002367 {
Geoff Langef7b0162014-09-04 13:29:23 -04002368 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2369 if (error.isError())
2370 {
2371 return error;
2372 }
2373
Brandon Jones142ec422014-07-16 10:31:30 -07002374 mDirtyImages = true;
2375 }
2376 else
2377 {
Geoff Langef7b0162014-09-04 13:29:23 -04002378 gl::Error error = ensureRenderTarget();
2379 if (error.isError())
2380 {
2381 return error;
2382 }
Brandon Jones142ec422014-07-16 10:31:30 -07002383
2384 if (isValidLevel(level))
2385 {
Geoff Langef7b0162014-09-04 13:29:23 -04002386 error = updateStorageLevel(level);
2387 if (error.isError())
2388 {
2389 return error;
2390 }
Brandon Jones142ec422014-07-16 10:31:30 -07002391
Geoff Langef7b0162014-09-04 13:29:23 -04002392 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2393 xoffset, yoffset, zoffset, mTexStorage, level);
2394 if (error.isError())
2395 {
2396 return error;
2397 }
Brandon Jones142ec422014-07-16 10:31:30 -07002398 }
2399 }
Geoff Langef7b0162014-09-04 13:29:23 -04002400 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002401}
2402
Geoff Lang1f8532b2014-09-05 09:46:13 -04002403gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002404{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002405 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2406
Brandon Jones142ec422014-07-16 10:31:30 -07002407 deleteImages();
2408
2409 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2410 {
2411 GLsizei levelWidth = std::max(1, width >> level);
2412 GLsizei levelHeight = std::max(1, height >> level);
2413
2414 mLayerCounts[level] = (level < levels ? depth : 0);
2415
2416 if (mLayerCounts[level] > 0)
2417 {
2418 // Create new images for this level
2419 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2420
2421 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2422 {
2423 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2424 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2425 levelHeight, 1, true);
2426 }
2427 }
2428 }
2429
Geoff Lang1f8532b2014-09-05 09:46:13 -04002430 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002431 bool renderTarget = IsRenderTargetUsage(mUsage);
2432 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002433
2434 gl::Error error = setCompleteTexStorage(storage);
2435 if (error.isError())
2436 {
2437 SafeDelete(storage);
2438 return error;
2439 }
2440
2441 mImmutable = true;
2442
2443 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002444}
2445
Brandon Jones6053a522014-07-25 16:22:09 -07002446void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002447{
Brandon Jones6053a522014-07-25 16:22:09 -07002448 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002449}
2450
Brandon Jones6053a522014-07-25 16:22:09 -07002451void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002452{
Brandon Jones6053a522014-07-25 16:22:09 -07002453 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002454}
2455
Brandon Jones6053a522014-07-25 16:22:09 -07002456
Jamie Madill4aa79e12014-09-29 10:46:14 -04002457void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002458{
2459 int baseWidth = getBaseLevelWidth();
2460 int baseHeight = getBaseLevelHeight();
2461 int baseDepth = getBaseLevelDepth();
2462 GLenum baseFormat = getBaseLevelInternalFormat();
2463
2464 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2465 int levelCount = mipLevels();
2466 for (int level = 1; level < levelCount; level++)
2467 {
2468 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2469 }
Brandon Jones142ec422014-07-16 10:31:30 -07002470}
2471
Jamie Madillac7579c2014-09-17 16:59:33 -04002472unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002473{
Geoff Langef7b0162014-09-04 13:29:23 -04002474 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002475}
2476
Geoff Lang64f23f62014-09-10 14:40:12 -04002477gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002478{
2479 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002480 gl::Error error = ensureRenderTarget();
2481 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002482 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002483 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002484 }
2485
Geoff Langef7b0162014-09-04 13:29:23 -04002486 error = updateStorageLevel(index.mipIndex);
2487 if (error.isError())
2488 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002489 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002490 }
2491
Geoff Lang64f23f62014-09-10 14:40:12 -04002492 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002493}
2494
Geoff Langef7b0162014-09-04 13:29:23 -04002495gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002496{
2497 // Only initialize the first time this texture is used as a render target or shader resource
2498 if (mTexStorage)
2499 {
Geoff Langef7b0162014-09-04 13:29:23 -04002500 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002501 }
2502
2503 // do not attempt to create storage for nonexistant data
2504 if (!isLevelComplete(0))
2505 {
Geoff Langef7b0162014-09-04 13:29:23 -04002506 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002507 }
2508
2509 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2510
Geoff Langef7b0162014-09-04 13:29:23 -04002511 TextureStorage *storage = NULL;
2512 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2513 if (error.isError())
2514 {
2515 return error;
2516 }
2517
2518 error = setCompleteTexStorage(storage);
2519 if (error.isError())
2520 {
2521 SafeDelete(storage);
2522 return error;
2523 }
2524
Brandon Jones142ec422014-07-16 10:31:30 -07002525 ASSERT(mTexStorage);
2526
2527 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002528 error = updateStorage();
2529 if (error.isError())
2530 {
2531 return error;
2532 }
2533
2534 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002535}
2536
Geoff Langef7b0162014-09-04 13:29:23 -04002537gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002538{
2539 GLsizei width = getBaseLevelWidth();
2540 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002541 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002542 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002543
2544 ASSERT(width > 0 && height > 0 && depth > 0);
2545
2546 // use existing storage level count, when previously specified by TexStorage*D
2547 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2548
Geoff Langef7b0162014-09-04 13:29:23 -04002549 // TODO(geofflang): Verify storage creation succeeds
2550 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2551
2552 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002553}
2554
Geoff Langef7b0162014-09-04 13:29:23 -04002555gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002556{
2557 SafeDelete(mTexStorage);
2558 mTexStorage = newCompleteTexStorage;
2559 mDirtyImages = true;
2560
2561 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2562 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002563
2564 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002565}
2566
Geoff Langef7b0162014-09-04 13:29:23 -04002567gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002568{
2569 ASSERT(mTexStorage != NULL);
2570 GLint storageLevels = mTexStorage->getLevelCount();
2571 for (int level = 0; level < storageLevels; level++)
2572 {
2573 if (isLevelComplete(level))
2574 {
Geoff Langef7b0162014-09-04 13:29:23 -04002575 gl::Error error = updateStorageLevel(level);
2576 if (error.isError())
2577 {
2578 return error;
2579 }
Brandon Jones142ec422014-07-16 10:31:30 -07002580 }
2581 }
Geoff Langef7b0162014-09-04 13:29:23 -04002582
2583 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002584}
2585
Brandon Jones142ec422014-07-16 10:31:30 -07002586bool TextureD3D_2DArray::isValidLevel(int level) const
2587{
2588 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2589}
2590
2591bool TextureD3D_2DArray::isLevelComplete(int level) const
2592{
2593 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2594
2595 if (isImmutable())
2596 {
2597 return true;
2598 }
2599
2600 GLsizei width = getBaseLevelWidth();
2601 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002602 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002603
2604 if (width <= 0 || height <= 0 || layers <= 0)
2605 {
2606 return false;
2607 }
2608
2609 if (level == 0)
2610 {
2611 return true;
2612 }
2613
2614 if (getInternalFormat(level) != getInternalFormat(0))
2615 {
2616 return false;
2617 }
2618
2619 if (getWidth(level) != std::max(1, width >> level))
2620 {
2621 return false;
2622 }
2623
2624 if (getHeight(level) != std::max(1, height >> level))
2625 {
2626 return false;
2627 }
2628
Jamie Madill3269bcb2014-09-30 16:33:52 -04002629 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002630 {
2631 return false;
2632 }
2633
2634 return true;
2635}
2636
Jamie Madille76bdda2014-10-20 17:13:52 -04002637bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2638{
2639 return isLevelComplete(index.mipIndex);
2640}
2641
Geoff Langef7b0162014-09-04 13:29:23 -04002642gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002643{
2644 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2645 ASSERT(isLevelComplete(level));
2646
2647 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2648 {
2649 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2650 if (mImageArray[level][layer]->isDirty())
2651 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002652 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2653 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002654 gl::Error error = commitRegion(index, region);
2655 if (error.isError())
2656 {
2657 return error;
2658 }
Brandon Jones142ec422014-07-16 10:31:30 -07002659 }
2660 }
Geoff Langef7b0162014-09-04 13:29:23 -04002661
2662 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002663}
2664
2665void TextureD3D_2DArray::deleteImages()
2666{
2667 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2668 {
2669 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2670 {
2671 delete mImageArray[level][layer];
2672 }
2673 delete[] mImageArray[level];
2674 mImageArray[level] = NULL;
2675 mLayerCounts[level] = 0;
2676 }
2677}
2678
2679void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2680{
2681 // If there currently is a corresponding storage texture image, it has these parameters
2682 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2683 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002684 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002685 const GLenum storageFormat = getBaseLevelInternalFormat();
2686
2687 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2688 {
2689 delete mImageArray[level][layer];
2690 }
2691 delete[] mImageArray[level];
2692 mImageArray[level] = NULL;
2693 mLayerCounts[level] = depth;
2694
2695 if (depth > 0)
2696 {
2697 mImageArray[level] = new ImageD3D*[depth]();
2698
2699 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2700 {
2701 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2702 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2703 }
2704 }
2705
2706 if (mTexStorage)
2707 {
2708 const int storageLevels = mTexStorage->getLevelCount();
2709
2710 if ((level >= storageLevels && storageLevels != 0) ||
2711 width != storageWidth ||
2712 height != storageHeight ||
2713 depth != storageDepth ||
2714 internalformat != storageFormat) // Discard mismatched storage
2715 {
2716 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2717 {
2718 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2719 {
2720 mImageArray[level][layer]->markDirty();
2721 }
2722 }
2723
2724 delete mTexStorage;
2725 mTexStorage = NULL;
2726 mDirtyImages = true;
2727 }
2728 }
2729}
2730
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002731gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2732{
2733 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2734}
2735
Jamie Madillcb83dc12014-09-29 10:46:12 -04002736gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2737{
2738 return gl::ImageIndex::Make2DArray(mip, layer);
2739}
2740
Jamie Madill710e5772014-10-20 17:13:53 -04002741bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2742{
2743 // Check for having a storage and the right type of index
2744 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2745 {
2746 return false;
2747 }
2748
2749 // Check the mip index
2750 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2751 {
2752 return false;
2753 }
2754
2755 // Check the layer index
2756 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2757}
2758
Brandon Jones78b1acd2014-07-15 15:33:07 -07002759}