blob: 0299920934bb36b71317c5f8a952cf070c54f789 [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 Madillba6bc952014-10-06 10:56:22 -040093gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
Jamie Madillba6bc952014-10-06 10:56:22 -040095 Image *image = getImage(index);
96
Brandon Jonesf47bebc2014-07-09 14:28:42 -070097 // No-op
98 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
99 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400100 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700101 }
102
103 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
104 // 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 -0400105 const uint8_t *pixelData = NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700106
107 if (unpack.pixelBuffer.id() != 0)
108 {
109 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
110 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
111 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
112 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
113 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
114 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400115 pixelData = static_cast<const uint8_t *>(bufferData) + offset;
116 }
117 else
118 {
119 pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700120 }
121
122 if (pixelData != NULL)
123 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400124 gl::Error error(GL_NO_ERROR);
125
126 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
127
128 // TODO(jmadill): Handle compressed internal formats
129 if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
130 {
131 gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
132 error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
133 }
134 else
135 {
136 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
137 }
138
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400139 if (error.isError())
140 {
141 return error;
142 }
143
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 mDirtyImages = true;
145 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400146
147 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148}
149
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400150gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
151 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152{
Jamie Madill9aca0592014-10-06 16:26:59 -0400153 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700154
155 // CPU readback & copy where direct GPU copy is not supported
156 if (unpack.pixelBuffer.id() != 0)
157 {
158 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200159 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700160 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
161 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
162 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400163 pixelData = static_cast<const uint8_t *>(bufferData)+offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700164 }
165
166 if (pixelData != NULL)
167 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400168 Image *image = getImage(index);
169 ASSERT(image);
170
Jamie Madill9aca0592014-10-06 16:26:59 -0400171 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
172 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
173
174 // TODO(jmadill): Handle compressed internal formats
175 if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
176 {
177 return mTexStorage->setData(index, region, image->getInternalFormat(),
178 type, unpack, pixelData);
179 }
180
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400181 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
182 type, pixelData);
183 if (error.isError())
184 {
185 return error;
186 }
187
Jamie Madille6b6da02014-10-02 11:03:14 -0400188 error = commitRegion(index, region);
189 if (error.isError())
190 {
191 return error;
192 }
193
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194 mDirtyImages = true;
195 }
196
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400197 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198}
199
Geoff Langb5348332014-09-02 13:16:34 -0400200gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700201{
202 if (pixels != NULL)
203 {
Geoff Langb5348332014-09-02 13:16:34 -0400204 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
205 if (error.isError())
206 {
207 return error;
208 }
209
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700210 mDirtyImages = true;
211 }
Geoff Langb5348332014-09-02 13:16:34 -0400212
213 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700214}
215
Geoff Langb5348332014-09-02 13:16:34 -0400216gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700217 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700218{
219 if (pixels != NULL)
220 {
Geoff Langb5348332014-09-02 13:16:34 -0400221 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
222 if (error.isError())
223 {
224 return error;
225 }
226
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227 mDirtyImages = true;
228 }
229
Geoff Langb5348332014-09-02 13:16:34 -0400230 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
233bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
234{
235 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
236}
237
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400238gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
239 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400241 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700242 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
243 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400244 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700245 }
246
247 // In order to perform the fast copy through the shader, we must have the right format, and be able
248 // to create a render target.
249 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
250
Jacek Cabana5521de2014-10-01 17:23:46 +0200251 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700252
Geoff Langae5122c2014-08-27 14:08:43 -0400253 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
254 if (error.isError())
255 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400256 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400257 }
258
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400259 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700260}
261
262GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
263{
264 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
265 {
266 // Maximum number of levels
267 return gl::log2(std::max(std::max(width, height), depth)) + 1;
268 }
269 else
270 {
271 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
272 return 1;
273 }
274}
275
276int TextureD3D::mipLevels() const
277{
278 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
279}
280
Jamie Madill98553e32014-09-30 16:33:50 -0400281TextureStorage *TextureD3D::getStorage()
282{
283 return mTexStorage;
284}
285
Jamie Madill3269bcb2014-09-30 16:33:52 -0400286Image *TextureD3D::getBaseLevelImage() const
287{
288 return getImage(getImageIndex(0, 0));
289}
290
Jamie Madill4aa79e12014-09-29 10:46:14 -0400291void TextureD3D::generateMipmaps()
292{
Jamie Madill9aca0592014-10-06 16:26:59 -0400293 GLint mipCount = mipLevels();
294
295 if (mipCount == 1)
296 {
297 return; // no-op
298 }
299
300 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400301 initMipmapsImages();
302
303 // We know that all layers have the same dimension, for the texture to be complete
304 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400305
Jamie Madill9aca0592014-10-06 16:26:59 -0400306 // When making mipmaps with the setData workaround enabled, the texture storage has
307 // the image data already. For non-render-target storage, we have to pull it out into
308 // an image layer.
309 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
310 {
311 if (!mTexStorage->isRenderTarget())
312 {
313 // Copy from the storage mip 0 to Image mip 0
314 for (GLint layer = 0; layer < layerCount; ++layer)
315 {
316 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400317
Jamie Madill9aca0592014-10-06 16:26:59 -0400318 Image *image = getImage(srcIndex);
319 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
320 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
321 }
322 }
323 else
324 {
325 updateStorage();
326 }
327 }
328
329 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400330
331 for (GLint layer = 0; layer < layerCount; ++layer)
332 {
333 for (GLint mip = 1; mip < mipCount; ++mip)
334 {
335 ASSERT(getLayerCount(mip) == layerCount);
336
337 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
338 gl::ImageIndex destIndex = getImageIndex(mip, layer);
339
340 if (renderableStorage)
341 {
342 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400343 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400344 }
345 else
346 {
347 // CPU-side mipmapping
348 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
349 }
350 }
351 }
352}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700353
Jamie Madill135570a2014-09-30 16:33:51 -0400354bool TextureD3D::isBaseImageZeroSize() const
355{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400356 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400357
358 if (!baseImage || baseImage->getWidth() <= 0)
359 {
360 return true;
361 }
362
363 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
364 {
365 return true;
366 }
367
368 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
369 {
370 return true;
371 }
372
373 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
374 {
375 return true;
376 }
377
378 return false;
379}
380
Geoff Langef7b0162014-09-04 13:29:23 -0400381gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400382{
Geoff Langef7b0162014-09-04 13:29:23 -0400383 gl::Error error = initializeStorage(true);
384 if (error.isError())
385 {
386 return error;
387 }
Jamie Madill135570a2014-09-30 16:33:51 -0400388
389 if (!isBaseImageZeroSize())
390 {
391 ASSERT(mTexStorage);
392 if (!mTexStorage->isRenderTarget())
393 {
Geoff Langef7b0162014-09-04 13:29:23 -0400394 TextureStorage *newRenderTargetStorage = NULL;
395 error = createCompleteStorage(true, &newRenderTargetStorage);
396 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400397 {
Geoff Langef7b0162014-09-04 13:29:23 -0400398 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400399 }
400
Geoff Langef7b0162014-09-04 13:29:23 -0400401 error = mTexStorage->copyToStorage(newRenderTargetStorage);
402 if (error.isError())
403 {
404 SafeDelete(newRenderTargetStorage);
405 return error;
406 }
407
408 error = setCompleteTexStorage(newRenderTargetStorage);
409 if (error.isError())
410 {
411 SafeDelete(newRenderTargetStorage);
412 return error;
413 }
Jamie Madill135570a2014-09-30 16:33:51 -0400414 }
415 }
416
Geoff Langef7b0162014-09-04 13:29:23 -0400417 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400418}
419
Brandon Jones78b1acd2014-07-15 15:33:07 -0700420TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400421 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700422{
423 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
424 {
425 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
426 }
427}
428
429TextureD3D_2D::~TextureD3D_2D()
430{
Austin Kinross69822602014-08-12 15:51:37 -0700431 // Delete the Images before the TextureStorage.
432 // Images might be relying on the TextureStorage for some of their data.
433 // 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 -0700434 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
435 {
436 delete mImageArray[i];
437 }
Austin Kinross69822602014-08-12 15:51:37 -0700438
439 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440}
441
Brandon Jonescef06ff2014-08-05 13:27:48 -0700442Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700443{
444 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700445 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700446 return mImageArray[level];
447}
448
Jamie Madillfeda4d22014-09-17 13:03:29 -0400449Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
450{
451 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400452 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400453 ASSERT(index.type == GL_TEXTURE_2D);
454 return mImageArray[index.mipIndex];
455}
456
Brandon Jonescef06ff2014-08-05 13:27:48 -0700457GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700458{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700459 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
460 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461}
462
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700463GLsizei TextureD3D_2D::getWidth(GLint level) const
464{
465 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
466 return mImageArray[level]->getWidth();
467 else
468 return 0;
469}
470
471GLsizei TextureD3D_2D::getHeight(GLint level) const
472{
473 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
474 return mImageArray[level]->getHeight();
475 else
476 return 0;
477}
478
479GLenum TextureD3D_2D::getInternalFormat(GLint level) const
480{
481 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
482 return mImageArray[level]->getInternalFormat();
483 else
484 return GL_NONE;
485}
486
487GLenum TextureD3D_2D::getActualFormat(GLint level) const
488{
489 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
490 return mImageArray[level]->getActualFormat();
491 else
492 return GL_NONE;
493}
494
495bool TextureD3D_2D::isDepth(GLint level) const
496{
Geoff Lang5d601382014-07-22 15:14:06 -0400497 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700498}
499
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400500gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
501 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
502 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700504 ASSERT(target == GL_TEXTURE_2D && depth == 1);
505
Geoff Lang5d601382014-07-22 15:14:06 -0400506 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
507
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700508 bool fastUnpacked = false;
509
Brandon Jonescef06ff2014-08-05 13:27:48 -0700510 redefineImage(level, sizedInternalFormat, width, height);
511
Jamie Madillba6bc952014-10-06 10:56:22 -0400512 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
513
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700514 // Attempt a fast gpu copy of the pixel data to the surface
515 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
516 {
517 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400518 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
520
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400521 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400523 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
524 if (error.isError())
525 {
526 return error;
527 }
528
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700529 // Ensure we don't overwrite our newly initialized data
530 mImageArray[level]->markClean();
531
532 fastUnpacked = true;
533 }
534 }
535
536 if (!fastUnpacked)
537 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400538 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400539 if (error.isError())
540 {
541 return error;
542 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400544
545 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700546}
547
Geoff Langb5348332014-09-02 13:16:34 -0400548gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
549 GLsizei width, GLsizei height, GLsizei depth,
550 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700552 ASSERT(target == GL_TEXTURE_2D && depth == 1);
553
554 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
555 redefineImage(level, format, width, height);
556
Geoff Langb5348332014-09-02 13:16:34 -0400557 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558}
559
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400560gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
561 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
562 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700563{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700564 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
565
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700566 bool fastUnpacked = false;
567
Jamie Madillac7579c2014-09-17 16:59:33 -0400568 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400569 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700570 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
571 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400572 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700573
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400574 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400576 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
577 if (error.isError())
578 {
579 return error;
580 }
581
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582 // Ensure we don't overwrite our newly initialized data
583 mImageArray[level]->markClean();
584
585 fastUnpacked = true;
586 }
587 }
588
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400589 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700590 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400591 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
592 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700593 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400594
595 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596}
597
Geoff Langb5348332014-09-02 13:16:34 -0400598gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
599 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
600 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700601{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700602 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
603
Geoff Langb5348332014-09-02 13:16:34 -0400604 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
605 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606 {
Geoff Langb5348332014-09-02 13:16:34 -0400607 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608 }
Geoff Langb5348332014-09-02 13:16:34 -0400609
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400610 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
611 gl::Box region(xoffset, yoffset, 0, width, height, 1);
612 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613}
614
Geoff Langef7b0162014-09-04 13:29:23 -0400615gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
616 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700617{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700618 ASSERT(target == GL_TEXTURE_2D);
619
620 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
621 redefineImage(level, sizedInternalFormat, width, height);
622
Jamie Madill82bf0c52014-10-03 11:50:53 -0400623 gl::Rectangle sourceRect(x, y, width, height);
624
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625 if (!mImageArray[level]->isRenderableFormat())
626 {
Geoff Langef7b0162014-09-04 13:29:23 -0400627 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
628 if (error.isError())
629 {
630 return error;
631 }
632
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700633 mDirtyImages = true;
634 }
635 else
636 {
Geoff Langef7b0162014-09-04 13:29:23 -0400637 gl::Error error = ensureRenderTarget();
638 if (error.isError())
639 {
640 return error;
641 }
642
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643 mImageArray[level]->markClean();
644
645 if (width != 0 && height != 0 && isValidLevel(level))
646 {
Geoff Langef7b0162014-09-04 13:29:23 -0400647 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
648 if (error.isError())
649 {
650 return error;
651 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652 }
653 }
Geoff Langef7b0162014-09-04 13:29:23 -0400654
655 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656}
657
Geoff Langef7b0162014-09-04 13:29:23 -0400658gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
659 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700660{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700661 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
662
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
664 // the current level we're copying to is defined (with appropriate format, width & height)
665 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
666
Jamie Madill82bf0c52014-10-03 11:50:53 -0400667 gl::Rectangle sourceRect(x, y, width, height);
668
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
670 {
Geoff Langef7b0162014-09-04 13:29:23 -0400671 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
672 if (error.isError())
673 {
674 return error;
675 }
676
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677 mDirtyImages = true;
678 }
679 else
680 {
Geoff Langef7b0162014-09-04 13:29:23 -0400681 gl::Error error = ensureRenderTarget();
682 if (error.isError())
683 {
684 return error;
685 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686
687 if (isValidLevel(level))
688 {
Geoff Langef7b0162014-09-04 13:29:23 -0400689 error = updateStorageLevel(level);
690 if (error.isError())
691 {
692 return error;
693 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694
Geoff Langef7b0162014-09-04 13:29:23 -0400695 error = mRenderer->copyImage2D(source, sourceRect,
696 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
697 xoffset, yoffset, mTexStorage, level);
698 if (error.isError())
699 {
700 return error;
701 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700702 }
703 }
Geoff Langef7b0162014-09-04 13:29:23 -0400704
705 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700706}
707
Geoff Lang1f8532b2014-09-05 09:46:13 -0400708gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700709{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700710 ASSERT(target == GL_TEXTURE_2D && depth == 1);
711
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712 for (int level = 0; level < levels; level++)
713 {
714 GLsizei levelWidth = std::max(1, width >> level);
715 GLsizei levelHeight = std::max(1, height >> level);
716 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
717 }
718
719 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
720 {
721 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
722 }
723
Geoff Lang1f8532b2014-09-05 09:46:13 -0400724 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400725 bool renderTarget = IsRenderTargetUsage(mUsage);
726 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400727
728 gl::Error error = setCompleteTexStorage(storage);
729 if (error.isError())
730 {
731 SafeDelete(storage);
732 return error;
733 }
734
735 mImmutable = true;
736
737 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700738}
739
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700740void TextureD3D_2D::bindTexImage(egl::Surface *surface)
741{
742 GLenum internalformat = surface->getFormat();
743
744 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
745
746 if (mTexStorage)
747 {
748 SafeDelete(mTexStorage);
749 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400750
751 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700752
753 mDirtyImages = true;
754}
755
756void TextureD3D_2D::releaseTexImage()
757{
758 if (mTexStorage)
759 {
760 SafeDelete(mTexStorage);
761 }
762
763 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
764 {
765 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
766 }
767}
768
Jamie Madill4aa79e12014-09-29 10:46:14 -0400769void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700771 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700772 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700773 for (int level = 1; level < levelCount; level++)
774 {
775 redefineImage(level, getBaseLevelInternalFormat(),
776 std::max(getBaseLevelWidth() >> level, 1),
777 std::max(getBaseLevelHeight() >> level, 1));
778 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700779}
780
Jamie Madillac7579c2014-09-17 16:59:33 -0400781unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700782{
Jamie Madillac7579c2014-09-17 16:59:33 -0400783 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400784 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785}
786
Jamie Madillac7579c2014-09-17 16:59:33 -0400787RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700788{
Jamie Madillac7579c2014-09-17 16:59:33 -0400789 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700790
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700791 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400792 gl::Error error = ensureRenderTarget();
793 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700794 {
795 return NULL;
796 }
797
Geoff Langef7b0162014-09-04 13:29:23 -0400798 error = updateStorageLevel(index.mipIndex);
799 if (error.isError())
800 {
801 return NULL;
802 }
803
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400804 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700805}
806
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700807bool TextureD3D_2D::isValidLevel(int level) const
808{
809 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
810}
811
812bool TextureD3D_2D::isLevelComplete(int level) const
813{
814 if (isImmutable())
815 {
816 return true;
817 }
818
Brandon Jones78b1acd2014-07-15 15:33:07 -0700819 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700820
821 GLsizei width = baseImage->getWidth();
822 GLsizei height = baseImage->getHeight();
823
824 if (width <= 0 || height <= 0)
825 {
826 return false;
827 }
828
829 // The base image level is complete if the width and height are positive
830 if (level == 0)
831 {
832 return true;
833 }
834
835 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700836 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700837
838 if (image->getInternalFormat() != baseImage->getInternalFormat())
839 {
840 return false;
841 }
842
843 if (image->getWidth() != std::max(1, width >> level))
844 {
845 return false;
846 }
847
848 if (image->getHeight() != std::max(1, height >> level))
849 {
850 return false;
851 }
852
853 return true;
854}
855
856// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400857gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700858{
859 // Only initialize the first time this texture is used as a render target or shader resource
860 if (mTexStorage)
861 {
Geoff Langef7b0162014-09-04 13:29:23 -0400862 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863 }
864
865 // do not attempt to create storage for nonexistant data
866 if (!isLevelComplete(0))
867 {
Geoff Langef7b0162014-09-04 13:29:23 -0400868 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869 }
870
871 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
872
Geoff Langef7b0162014-09-04 13:29:23 -0400873 TextureStorage *storage = NULL;
874 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
875 if (error.isError())
876 {
877 return error;
878 }
879
880 error = setCompleteTexStorage(storage);
881 if (error.isError())
882 {
883 SafeDelete(storage);
884 return error;
885 }
886
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700887 ASSERT(mTexStorage);
888
889 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400890 error = updateStorage();
891 if (error.isError())
892 {
893 return error;
894 }
895
896 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700897}
898
Geoff Langef7b0162014-09-04 13:29:23 -0400899gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700900{
901 GLsizei width = getBaseLevelWidth();
902 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400903 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700904
905 ASSERT(width > 0 && height > 0);
906
907 // use existing storage level count, when previously specified by TexStorage*D
908 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
909
Geoff Langef7b0162014-09-04 13:29:23 -0400910 // TODO(geofflang): Determine if the texture creation succeeded
911 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
912
913 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700914}
915
Geoff Langef7b0162014-09-04 13:29:23 -0400916gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700917{
Geoff Langef7b0162014-09-04 13:29:23 -0400918 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919 {
Geoff Langef7b0162014-09-04 13:29:23 -0400920 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700921 {
Geoff Langef7b0162014-09-04 13:29:23 -0400922 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
923 if (error.isError())
924 {
925 return error;
926 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700927 }
928 }
929
Geoff Langef7b0162014-09-04 13:29:23 -0400930 SafeDelete(mTexStorage);
931 mTexStorage = newCompleteTexStorage;
932
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700933 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400934
935 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700936}
937
Geoff Langef7b0162014-09-04 13:29:23 -0400938gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700939{
940 ASSERT(mTexStorage != NULL);
941 GLint storageLevels = mTexStorage->getLevelCount();
942 for (int level = 0; level < storageLevels; level++)
943 {
944 if (mImageArray[level]->isDirty() && isLevelComplete(level))
945 {
Geoff Langef7b0162014-09-04 13:29:23 -0400946 gl::Error error = updateStorageLevel(level);
947 if (error.isError())
948 {
949 return error;
950 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700951 }
952 }
Geoff Langef7b0162014-09-04 13:29:23 -0400953
954 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700955}
956
Geoff Langef7b0162014-09-04 13:29:23 -0400957gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700958{
959 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
960 ASSERT(isLevelComplete(level));
961
962 if (mImageArray[level]->isDirty())
963 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400964 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
965 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -0400966 gl::Error error = commitRegion(index, region);
967 if (error.isError())
968 {
969 return error;
970 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700971 }
Geoff Langef7b0162014-09-04 13:29:23 -0400972
973 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700974}
975
976void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
977{
978 // If there currently is a corresponding storage texture image, it has these parameters
979 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
980 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
981 const GLenum storageFormat = getBaseLevelInternalFormat();
982
983 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
984
985 if (mTexStorage)
986 {
987 const int storageLevels = mTexStorage->getLevelCount();
988
989 if ((level >= storageLevels && storageLevels != 0) ||
990 width != storageWidth ||
991 height != storageHeight ||
992 internalformat != storageFormat) // Discard mismatched storage
993 {
994 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
995 {
996 mImageArray[i]->markDirty();
997 }
998
999 SafeDelete(mTexStorage);
1000 mDirtyImages = true;
1001 }
1002 }
1003}
1004
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001005gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001006{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001007 ASSERT(!index.hasLayer());
1008 GLint level = index.mipIndex;
1009
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001010 if (isValidLevel(level))
1011 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001012 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001013 gl::Error error = image->copyToStorage2D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001014 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001015 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001016 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001017 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001018
1019 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001020 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001021
1022 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001023}
1024
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001025gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1026{
1027 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1028}
Brandon Jones0511e802014-07-14 16:27:26 -07001029
Jamie Madillcb83dc12014-09-29 10:46:12 -04001030gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1031{
1032 // "layer" does not apply to 2D Textures.
1033 return gl::ImageIndex::Make2D(mip);
1034}
1035
Brandon Jones78b1acd2014-07-15 15:33:07 -07001036TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001037 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001038{
1039 for (int i = 0; i < 6; i++)
1040 {
1041 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1042 {
1043 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1044 }
1045 }
1046}
1047
1048TextureD3D_Cube::~TextureD3D_Cube()
1049{
Austin Kinross69822602014-08-12 15:51:37 -07001050 // Delete the Images before the TextureStorage.
1051 // Images might be relying on the TextureStorage for some of their data.
1052 // 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 -07001053 for (int i = 0; i < 6; i++)
1054 {
1055 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1056 {
1057 SafeDelete(mImageArray[i][j]);
1058 }
1059 }
Austin Kinross69822602014-08-12 15:51:37 -07001060
1061 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001062}
1063
Brandon Jonescef06ff2014-08-05 13:27:48 -07001064Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001065{
1066 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001067 ASSERT(layer < 6);
1068 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001069}
1070
Jamie Madillfeda4d22014-09-17 13:03:29 -04001071Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1072{
1073 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1074 ASSERT(index.layerIndex < 6);
1075 return mImageArray[index.layerIndex][index.mipIndex];
1076}
1077
Brandon Jonescef06ff2014-08-05 13:27:48 -07001078GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001079{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001080 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1081 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001082}
1083
Brandon Jonescef06ff2014-08-05 13:27:48 -07001084GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001085{
1086 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001087 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001088 else
1089 return GL_NONE;
1090}
1091
Brandon Jonescef06ff2014-08-05 13:27:48 -07001092bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001093{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001094 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001095}
1096
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001097gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1098 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1099 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001100{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001101 ASSERT(depth == 1);
1102
Geoff Lang5d601382014-07-22 15:14:06 -04001103 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001104 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001105
Jamie Madillba6bc952014-10-06 10:56:22 -04001106 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001107
Jamie Madillba6bc952014-10-06 10:56:22 -04001108 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001109}
1110
Geoff Langb5348332014-09-02 13:16:34 -04001111gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1112 GLsizei width, GLsizei height, GLsizei depth,
1113 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001114{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001115 ASSERT(depth == 1);
1116
Brandon Jones0511e802014-07-14 16:27:26 -07001117 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001118 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1119
Brandon Jones0511e802014-07-14 16:27:26 -07001120 redefineImage(faceIndex, level, format, width, height);
1121
Geoff Langb5348332014-09-02 13:16:34 -04001122 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001123}
1124
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001125gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1126 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1127 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001128{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001129 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001130 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001131 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001132}
1133
Geoff Langb5348332014-09-02 13:16:34 -04001134gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1135 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1136 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001137{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001138 ASSERT(depth == 1 && zoffset == 0);
1139
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001140 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001141
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001142 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 -04001143 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001144 {
Geoff Langb5348332014-09-02 13:16:34 -04001145 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001146 }
Geoff Langb5348332014-09-02 13:16:34 -04001147
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001148 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1149 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001150}
1151
Geoff Langef7b0162014-09-04 13:29:23 -04001152gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1153 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001154{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001155 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001156 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1157
Brandon Jones0511e802014-07-14 16:27:26 -07001158 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1159
Jamie Madill82bf0c52014-10-03 11:50:53 -04001160 gl::Rectangle sourceRect(x, y, width, height);
1161
Brandon Jones0511e802014-07-14 16:27:26 -07001162 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1163 {
Geoff Langef7b0162014-09-04 13:29:23 -04001164 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1165 if (error.isError())
1166 {
1167 return error;
1168 }
1169
Brandon Jones0511e802014-07-14 16:27:26 -07001170 mDirtyImages = true;
1171 }
1172 else
1173 {
Geoff Langef7b0162014-09-04 13:29:23 -04001174 gl::Error error = ensureRenderTarget();
1175 if (error.isError())
1176 {
1177 return error;
1178 }
1179
Brandon Jones0511e802014-07-14 16:27:26 -07001180 mImageArray[faceIndex][level]->markClean();
1181
1182 ASSERT(width == height);
1183
1184 if (width > 0 && isValidFaceLevel(faceIndex, level))
1185 {
Geoff Langef7b0162014-09-04 13:29:23 -04001186 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1187 if (error.isError())
1188 {
1189 return error;
1190 }
Brandon Jones0511e802014-07-14 16:27:26 -07001191 }
1192 }
Geoff Langef7b0162014-09-04 13:29:23 -04001193
1194 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001195}
1196
Geoff Langef7b0162014-09-04 13:29:23 -04001197gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1198 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001199{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001200 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001201
1202 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1203 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1204 // rely on the "getBaseLevel*" methods reliably otherwise.
1205 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1206
Jamie Madill82bf0c52014-10-03 11:50:53 -04001207 gl::Rectangle sourceRect(x, y, width, height);
1208
Brandon Jones0511e802014-07-14 16:27:26 -07001209 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1210 {
Geoff Langef7b0162014-09-04 13:29:23 -04001211 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1212 if (error.isError())
1213 {
1214 return error;
1215 }
1216
Brandon Jones0511e802014-07-14 16:27:26 -07001217 mDirtyImages = true;
1218 }
1219 else
1220 {
Geoff Langef7b0162014-09-04 13:29:23 -04001221 gl::Error error = ensureRenderTarget();
1222 if (error.isError())
1223 {
1224 return error;
1225 }
Brandon Jones0511e802014-07-14 16:27:26 -07001226
1227 if (isValidFaceLevel(faceIndex, level))
1228 {
Geoff Langef7b0162014-09-04 13:29:23 -04001229 error = updateStorageFaceLevel(faceIndex, level);
1230 if (error.isError())
1231 {
1232 return error;
1233 }
Brandon Jones0511e802014-07-14 16:27:26 -07001234
Geoff Langef7b0162014-09-04 13:29:23 -04001235 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1236 xoffset, yoffset, mTexStorage, target, level);
1237 if (error.isError())
1238 {
1239 return error;
1240 }
Brandon Jones0511e802014-07-14 16:27:26 -07001241 }
1242 }
Geoff Langef7b0162014-09-04 13:29:23 -04001243
1244 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001245}
1246
Geoff Lang1f8532b2014-09-05 09:46:13 -04001247gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001248{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001249 ASSERT(width == height);
1250 ASSERT(depth == 1);
1251
Brandon Jones0511e802014-07-14 16:27:26 -07001252 for (int level = 0; level < levels; level++)
1253 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001254 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001255 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1256 {
1257 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1258 }
1259 }
1260
1261 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1262 {
1263 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1264 {
1265 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1266 }
1267 }
1268
Geoff Lang1f8532b2014-09-05 09:46:13 -04001269 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001270 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001271 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001272
1273 gl::Error error = setCompleteTexStorage(storage);
1274 if (error.isError())
1275 {
1276 SafeDelete(storage);
1277 return error;
1278 }
1279
1280 mImmutable = true;
1281
1282 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001283}
1284
Brandon Jones0511e802014-07-14 16:27:26 -07001285// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1286bool TextureD3D_Cube::isCubeComplete() const
1287{
1288 int baseWidth = getBaseLevelWidth();
1289 int baseHeight = getBaseLevelHeight();
1290 GLenum baseFormat = getBaseLevelInternalFormat();
1291
1292 if (baseWidth <= 0 || baseWidth != baseHeight)
1293 {
1294 return false;
1295 }
1296
1297 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1298 {
1299 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1300
1301 if (faceBaseImage.getWidth() != baseWidth ||
1302 faceBaseImage.getHeight() != baseHeight ||
1303 faceBaseImage.getInternalFormat() != baseFormat )
1304 {
1305 return false;
1306 }
1307 }
1308
1309 return true;
1310}
1311
Brandon Jones6053a522014-07-25 16:22:09 -07001312void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1313{
1314 UNREACHABLE();
1315}
1316
1317void TextureD3D_Cube::releaseTexImage()
1318{
1319 UNREACHABLE();
1320}
1321
1322
Jamie Madill4aa79e12014-09-29 10:46:14 -04001323void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001324{
1325 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1326 int levelCount = mipLevels();
1327 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1328 {
1329 for (int level = 1; level < levelCount; level++)
1330 {
1331 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1332 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1333 }
1334 }
Brandon Jones0511e802014-07-14 16:27:26 -07001335}
1336
Jamie Madillac7579c2014-09-17 16:59:33 -04001337unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001338{
Geoff Langef7b0162014-09-04 13:29:23 -04001339 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001340}
1341
Jamie Madillac7579c2014-09-17 16:59:33 -04001342RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001343{
Jamie Madillac7579c2014-09-17 16:59:33 -04001344 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001345
1346 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001347 gl::Error error = ensureRenderTarget();
1348 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001349 {
1350 return NULL;
1351 }
1352
Geoff Langef7b0162014-09-04 13:29:23 -04001353 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1354 if (error.isError())
1355 {
1356 return NULL;
1357 }
1358
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001359 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001360}
1361
Geoff Langef7b0162014-09-04 13:29:23 -04001362gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001363{
1364 // Only initialize the first time this texture is used as a render target or shader resource
1365 if (mTexStorage)
1366 {
Geoff Langef7b0162014-09-04 13:29:23 -04001367 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001368 }
1369
1370 // do not attempt to create storage for nonexistant data
1371 if (!isFaceLevelComplete(0, 0))
1372 {
Geoff Langef7b0162014-09-04 13:29:23 -04001373 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001374 }
1375
1376 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1377
Geoff Langef7b0162014-09-04 13:29:23 -04001378 TextureStorage *storage = NULL;
1379 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1380 if (error.isError())
1381 {
1382 return error;
1383 }
1384
1385 error = setCompleteTexStorage(storage);
1386 if (error.isError())
1387 {
1388 SafeDelete(storage);
1389 return error;
1390 }
1391
Brandon Jones0511e802014-07-14 16:27:26 -07001392 ASSERT(mTexStorage);
1393
1394 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001395 error = updateStorage();
1396 if (error.isError())
1397 {
1398 return error;
1399 }
1400
1401 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001402}
1403
Geoff Langef7b0162014-09-04 13:29:23 -04001404gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001405{
1406 GLsizei size = getBaseLevelWidth();
1407
1408 ASSERT(size > 0);
1409
1410 // use existing storage level count, when previously specified by TexStorage*D
1411 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1412
Geoff Langef7b0162014-09-04 13:29:23 -04001413 // TODO (geofflang): detect if storage creation succeeded
1414 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1415
1416 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001417}
1418
Geoff Langef7b0162014-09-04 13:29:23 -04001419gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001420{
Geoff Langef7b0162014-09-04 13:29:23 -04001421 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001422 {
1423 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1424 {
Geoff Langef7b0162014-09-04 13:29:23 -04001425 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001426 {
Geoff Langef7b0162014-09-04 13:29:23 -04001427 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1428 if (error.isError())
1429 {
1430 return error;
1431 }
Brandon Jones0511e802014-07-14 16:27:26 -07001432 }
1433 }
1434 }
1435
Geoff Langef7b0162014-09-04 13:29:23 -04001436 SafeDelete(mTexStorage);
1437 mTexStorage = newCompleteTexStorage;
1438
Brandon Jones0511e802014-07-14 16:27:26 -07001439 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001440 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001441}
1442
Geoff Langef7b0162014-09-04 13:29:23 -04001443gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001444{
1445 ASSERT(mTexStorage != NULL);
1446 GLint storageLevels = mTexStorage->getLevelCount();
1447 for (int face = 0; face < 6; face++)
1448 {
1449 for (int level = 0; level < storageLevels; level++)
1450 {
1451 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1452 {
Geoff Langef7b0162014-09-04 13:29:23 -04001453 gl::Error error = updateStorageFaceLevel(face, level);
1454 if (error.isError())
1455 {
1456 return error;
1457 }
Brandon Jones0511e802014-07-14 16:27:26 -07001458 }
1459 }
1460 }
Geoff Langef7b0162014-09-04 13:29:23 -04001461
1462 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001463}
1464
Brandon Jones0511e802014-07-14 16:27:26 -07001465bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1466{
1467 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1468}
1469
Brandon Jones0511e802014-07-14 16:27:26 -07001470bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1471{
1472 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1473
1474 if (isImmutable())
1475 {
1476 return true;
1477 }
1478
1479 int baseSize = getBaseLevelWidth();
1480
1481 if (baseSize <= 0)
1482 {
1483 return false;
1484 }
1485
1486 // "isCubeComplete" checks for base level completeness and we must call that
1487 // to determine if any face at level 0 is complete. We omit that check here
1488 // to avoid re-checking cube-completeness for every face at level 0.
1489 if (level == 0)
1490 {
1491 return true;
1492 }
1493
1494 // Check that non-zero levels are consistent with the base level.
1495 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1496
1497 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1498 {
1499 return false;
1500 }
1501
1502 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1503 {
1504 return false;
1505 }
1506
1507 return true;
1508}
1509
Geoff Langef7b0162014-09-04 13:29:23 -04001510gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001511{
1512 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1513 ImageD3D *image = mImageArray[faceIndex][level];
1514
1515 if (image->isDirty())
1516 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001517 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1518 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1519 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001520 gl::Error error = commitRegion(index, region);
1521 if (error.isError())
1522 {
1523 return error;
1524 }
Brandon Jones0511e802014-07-14 16:27:26 -07001525 }
Geoff Langef7b0162014-09-04 13:29:23 -04001526
1527 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001528}
1529
1530void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1531{
1532 // If there currently is a corresponding storage texture image, it has these parameters
1533 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1534 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1535 const GLenum storageFormat = getBaseLevelInternalFormat();
1536
1537 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1538
1539 if (mTexStorage)
1540 {
1541 const int storageLevels = mTexStorage->getLevelCount();
1542
1543 if ((level >= storageLevels && storageLevels != 0) ||
1544 width != storageWidth ||
1545 height != storageHeight ||
1546 internalformat != storageFormat) // Discard mismatched storage
1547 {
1548 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1549 {
1550 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1551 {
1552 mImageArray[faceIndex][level]->markDirty();
1553 }
1554 }
1555
1556 SafeDelete(mTexStorage);
1557
1558 mDirtyImages = true;
1559 }
1560 }
1561}
1562
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001563gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001564{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001565 ASSERT(index.hasLayer());
1566
1567 GLint level = index.mipIndex;
1568 int faceIndex = static_cast<int>(index.layerIndex);
1569
Brandon Jones0511e802014-07-14 16:27:26 -07001570 if (isValidFaceLevel(faceIndex, level))
1571 {
1572 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001573 gl::Error error = image->copyToStorageCube(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001574 if (error.isError())
1575 {
1576 return error;
1577 }
1578
1579 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001580 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001581
1582 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001583}
1584
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001585gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1586{
1587 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1588}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001589
Jamie Madillcb83dc12014-09-29 10:46:12 -04001590gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1591{
1592 // The "layer" of the image index corresponds to the cube face
1593 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1594}
1595
Brandon Jones78b1acd2014-07-15 15:33:07 -07001596TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001597 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001598{
1599 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1600 {
1601 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1602 }
1603}
1604
1605TextureD3D_3D::~TextureD3D_3D()
1606{
Austin Kinross69822602014-08-12 15:51:37 -07001607 // Delete the Images before the TextureStorage.
1608 // Images might be relying on the TextureStorage for some of their data.
1609 // 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 -07001610 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1611 {
1612 delete mImageArray[i];
1613 }
Austin Kinross69822602014-08-12 15:51:37 -07001614
1615 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616}
1617
Brandon Jonescef06ff2014-08-05 13:27:48 -07001618Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001619{
1620 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001621 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001622 return mImageArray[level];
1623}
1624
Jamie Madillfeda4d22014-09-17 13:03:29 -04001625Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1626{
1627 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001628 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001629 ASSERT(index.type == GL_TEXTURE_3D);
1630 return mImageArray[index.mipIndex];
1631}
1632
Brandon Jonescef06ff2014-08-05 13:27:48 -07001633GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001635 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1636 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001637}
1638
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639GLsizei TextureD3D_3D::getWidth(GLint level) const
1640{
1641 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1642 return mImageArray[level]->getWidth();
1643 else
1644 return 0;
1645}
1646
1647GLsizei TextureD3D_3D::getHeight(GLint level) const
1648{
1649 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1650 return mImageArray[level]->getHeight();
1651 else
1652 return 0;
1653}
1654
1655GLsizei TextureD3D_3D::getDepth(GLint level) const
1656{
1657 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1658 return mImageArray[level]->getDepth();
1659 else
1660 return 0;
1661}
1662
1663GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1664{
1665 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1666 return mImageArray[level]->getInternalFormat();
1667 else
1668 return GL_NONE;
1669}
1670
1671bool TextureD3D_3D::isDepth(GLint level) const
1672{
Geoff Lang5d601382014-07-22 15:14:06 -04001673 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674}
1675
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001676gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1677 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1678 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001679{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001680 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001681 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1682
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683 redefineImage(level, sizedInternalFormat, width, height, depth);
1684
1685 bool fastUnpacked = false;
1686
Jamie Madillba6bc952014-10-06 10:56:22 -04001687 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1688
Brandon Jones78b1acd2014-07-15 15:33:07 -07001689 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1690 if (isFastUnpackable(unpack, sizedInternalFormat))
1691 {
1692 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001693 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001694 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1695
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001696 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001698 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1699 if (error.isError())
1700 {
1701 return error;
1702 }
1703
Brandon Jones78b1acd2014-07-15 15:33:07 -07001704 // Ensure we don't overwrite our newly initialized data
1705 mImageArray[level]->markClean();
1706
1707 fastUnpacked = true;
1708 }
1709 }
1710
1711 if (!fastUnpacked)
1712 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001713 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001714 if (error.isError())
1715 {
1716 return error;
1717 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001718 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001719
1720 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001721}
1722
Geoff Langb5348332014-09-02 13:16:34 -04001723gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1724 GLsizei width, GLsizei height,GLsizei depth,
1725 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001726{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001727 ASSERT(target == GL_TEXTURE_3D);
1728
Brandon Jones78b1acd2014-07-15 15:33:07 -07001729 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1730 redefineImage(level, format, width, height, depth);
1731
Geoff Langb5348332014-09-02 13:16:34 -04001732 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001733}
1734
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001735gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1736 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1737 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001738{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001739 ASSERT(target == GL_TEXTURE_3D);
1740
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741 bool fastUnpacked = false;
1742
Jamie Madillac7579c2014-09-17 16:59:33 -04001743 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1744
Brandon Jones78b1acd2014-07-15 15:33:07 -07001745 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1746 if (isFastUnpackable(unpack, getInternalFormat(level)))
1747 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001748 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001749
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001750 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001751 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001752 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001753 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1754 if (error.isError())
1755 {
1756 return error;
1757 }
1758
Brandon Jones78b1acd2014-07-15 15:33:07 -07001759 // Ensure we don't overwrite our newly initialized data
1760 mImageArray[level]->markClean();
1761
1762 fastUnpacked = true;
1763 }
1764 }
1765
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001766 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001767 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001768 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1769 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001770 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001771
1772 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001773}
1774
Geoff Langb5348332014-09-02 13:16:34 -04001775gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1776 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1777 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001778{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001779 ASSERT(target == GL_TEXTURE_3D);
1780
Geoff Langb5348332014-09-02 13:16:34 -04001781 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1782 format, imageSize, pixels, mImageArray[level]);
1783 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001784 {
Geoff Langb5348332014-09-02 13:16:34 -04001785 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001786 }
Geoff Langb5348332014-09-02 13:16:34 -04001787
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001788 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1789 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1790 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791}
1792
Geoff Langef7b0162014-09-04 13:29:23 -04001793gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1794 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001795{
1796 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001797 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001798}
1799
Geoff Langef7b0162014-09-04 13:29:23 -04001800gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1801 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001803 ASSERT(target == GL_TEXTURE_3D);
1804
Brandon Jones78b1acd2014-07-15 15:33:07 -07001805 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1806 // the current level we're copying to is defined (with appropriate format, width & height)
1807 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1808
Jamie Madill82bf0c52014-10-03 11:50:53 -04001809 gl::Rectangle sourceRect(x, y, width, height);
1810
Brandon Jones78b1acd2014-07-15 15:33:07 -07001811 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1812 {
Geoff Langef7b0162014-09-04 13:29:23 -04001813 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1814 if (error.isError())
1815 {
1816 return error;
1817 }
1818
Brandon Jones78b1acd2014-07-15 15:33:07 -07001819 mDirtyImages = true;
1820 }
1821 else
1822 {
Geoff Langef7b0162014-09-04 13:29:23 -04001823 gl::Error error = ensureRenderTarget();
1824 if (error.isError())
1825 {
1826 return error;
1827 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001828
1829 if (isValidLevel(level))
1830 {
Geoff Langef7b0162014-09-04 13:29:23 -04001831 error = updateStorageLevel(level);
1832 if (error.isError())
1833 {
1834 return error;
1835 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001836
Geoff Langef7b0162014-09-04 13:29:23 -04001837 error = mRenderer->copyImage3D(source, sourceRect,
1838 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1839 xoffset, yoffset, zoffset, mTexStorage, level);
1840 if (error.isError())
1841 {
1842 return error;
1843 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844 }
1845 }
Geoff Langef7b0162014-09-04 13:29:23 -04001846
1847 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848}
1849
Geoff Lang1f8532b2014-09-05 09:46:13 -04001850gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001851{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001852 ASSERT(target == GL_TEXTURE_3D);
1853
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854 for (int level = 0; level < levels; level++)
1855 {
1856 GLsizei levelWidth = std::max(1, width >> level);
1857 GLsizei levelHeight = std::max(1, height >> level);
1858 GLsizei levelDepth = std::max(1, depth >> level);
1859 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1860 }
1861
1862 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1863 {
1864 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1865 }
1866
Geoff Lang1f8532b2014-09-05 09:46:13 -04001867 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001868 bool renderTarget = IsRenderTargetUsage(mUsage);
1869 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001870
1871 gl::Error error = setCompleteTexStorage(storage);
1872 if (error.isError())
1873 {
1874 SafeDelete(storage);
1875 return error;
1876 }
1877
1878 mImmutable = true;
1879
1880 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001881}
1882
Brandon Jones6053a522014-07-25 16:22:09 -07001883void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001884{
Brandon Jones6053a522014-07-25 16:22:09 -07001885 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001886}
1887
Brandon Jones6053a522014-07-25 16:22:09 -07001888void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001889{
Brandon Jones6053a522014-07-25 16:22:09 -07001890 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001891}
1892
Brandon Jones6053a522014-07-25 16:22:09 -07001893
Jamie Madill4aa79e12014-09-29 10:46:14 -04001894void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001895{
1896 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1897 int levelCount = mipLevels();
1898 for (int level = 1; level < levelCount; level++)
1899 {
1900 redefineImage(level, getBaseLevelInternalFormat(),
1901 std::max(getBaseLevelWidth() >> level, 1),
1902 std::max(getBaseLevelHeight() >> level, 1),
1903 std::max(getBaseLevelDepth() >> level, 1));
1904 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001905}
1906
Jamie Madillac7579c2014-09-17 16:59:33 -04001907unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001908{
Geoff Langef7b0162014-09-04 13:29:23 -04001909 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001910}
1911
Jamie Madillac7579c2014-09-17 16:59:33 -04001912RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001913{
1914 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001915 gl::Error error = ensureRenderTarget();
1916 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917 {
1918 return NULL;
1919 }
1920
Jamie Madillac7579c2014-09-17 16:59:33 -04001921 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001922 {
Geoff Langef7b0162014-09-04 13:29:23 -04001923 error = updateStorage();
1924 if (error.isError())
1925 {
1926 return NULL;
1927 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001928 }
1929 else
1930 {
Geoff Langef7b0162014-09-04 13:29:23 -04001931 error = updateStorageLevel(index.mipIndex);
1932 if (error.isError())
1933 {
1934 return NULL;
1935 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001936 }
1937
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001938 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001939}
1940
Geoff Langef7b0162014-09-04 13:29:23 -04001941gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001942{
1943 // Only initialize the first time this texture is used as a render target or shader resource
1944 if (mTexStorage)
1945 {
Geoff Langef7b0162014-09-04 13:29:23 -04001946 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001947 }
1948
1949 // do not attempt to create storage for nonexistant data
1950 if (!isLevelComplete(0))
1951 {
Geoff Langef7b0162014-09-04 13:29:23 -04001952 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001953 }
1954
1955 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1956
Geoff Langef7b0162014-09-04 13:29:23 -04001957 rx::TextureStorage *storage = NULL;
1958 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1959 if (error.isError())
1960 {
1961 return error;
1962 }
1963
1964 error = setCompleteTexStorage(storage);
1965 if (error.isError())
1966 {
1967 SafeDelete(storage);
1968 return error;
1969 }
1970
Brandon Jones78b1acd2014-07-15 15:33:07 -07001971 ASSERT(mTexStorage);
1972
1973 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001974 error = updateStorage();
1975 if (error.isError())
1976 {
1977 return error;
1978 }
1979
1980 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001981}
1982
Geoff Langef7b0162014-09-04 13:29:23 -04001983gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001984{
1985 GLsizei width = getBaseLevelWidth();
1986 GLsizei height = getBaseLevelHeight();
1987 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001988 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001989
1990 ASSERT(width > 0 && height > 0 && depth > 0);
1991
1992 // use existing storage level count, when previously specified by TexStorage*D
1993 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1994
Geoff Langef7b0162014-09-04 13:29:23 -04001995 // TODO: Verify creation of the storage succeeded
1996 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
1997
1998 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001999}
2000
Geoff Langef7b0162014-09-04 13:29:23 -04002001gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002{
2003 SafeDelete(mTexStorage);
2004 mTexStorage = newCompleteTexStorage;
2005 mDirtyImages = true;
2006
2007 // We do not support managed 3D storage, as that is D3D9/ES2-only
2008 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002009
2010 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002011}
2012
Geoff Langef7b0162014-09-04 13:29:23 -04002013gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002014{
2015 ASSERT(mTexStorage != NULL);
2016 GLint storageLevels = mTexStorage->getLevelCount();
2017 for (int level = 0; level < storageLevels; level++)
2018 {
2019 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2020 {
Geoff Langef7b0162014-09-04 13:29:23 -04002021 gl::Error error = updateStorageLevel(level);
2022 if (error.isError())
2023 {
2024 return error;
2025 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002026 }
2027 }
Geoff Langef7b0162014-09-04 13:29:23 -04002028
2029 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002030}
2031
Brandon Jones78b1acd2014-07-15 15:33:07 -07002032bool TextureD3D_3D::isValidLevel(int level) const
2033{
2034 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2035}
2036
2037bool TextureD3D_3D::isLevelComplete(int level) const
2038{
2039 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2040
2041 if (isImmutable())
2042 {
2043 return true;
2044 }
2045
2046 GLsizei width = getBaseLevelWidth();
2047 GLsizei height = getBaseLevelHeight();
2048 GLsizei depth = getBaseLevelDepth();
2049
2050 if (width <= 0 || height <= 0 || depth <= 0)
2051 {
2052 return false;
2053 }
2054
2055 if (level == 0)
2056 {
2057 return true;
2058 }
2059
2060 ImageD3D *levelImage = mImageArray[level];
2061
2062 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2063 {
2064 return false;
2065 }
2066
2067 if (levelImage->getWidth() != std::max(1, width >> level))
2068 {
2069 return false;
2070 }
2071
2072 if (levelImage->getHeight() != std::max(1, height >> level))
2073 {
2074 return false;
2075 }
2076
2077 if (levelImage->getDepth() != std::max(1, depth >> level))
2078 {
2079 return false;
2080 }
2081
2082 return true;
2083}
2084
Geoff Langef7b0162014-09-04 13:29:23 -04002085gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002086{
2087 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2088 ASSERT(isLevelComplete(level));
2089
2090 if (mImageArray[level]->isDirty())
2091 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002092 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2093 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002094 gl::Error error = commitRegion(index, region);
2095 if (error.isError())
2096 {
2097 return error;
2098 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099 }
Geoff Langef7b0162014-09-04 13:29:23 -04002100
2101 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002102}
2103
2104void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2105{
2106 // If there currently is a corresponding storage texture image, it has these parameters
2107 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2108 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2109 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2110 const GLenum storageFormat = getBaseLevelInternalFormat();
2111
2112 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2113
2114 if (mTexStorage)
2115 {
2116 const int storageLevels = mTexStorage->getLevelCount();
2117
2118 if ((level >= storageLevels && storageLevels != 0) ||
2119 width != storageWidth ||
2120 height != storageHeight ||
2121 depth != storageDepth ||
2122 internalformat != storageFormat) // Discard mismatched storage
2123 {
2124 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2125 {
2126 mImageArray[i]->markDirty();
2127 }
2128
2129 SafeDelete(mTexStorage);
2130 mDirtyImages = true;
2131 }
2132 }
2133}
2134
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002135gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002136{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002137 ASSERT(!index.hasLayer());
2138 GLint level = index.mipIndex;
2139
Brandon Jones78b1acd2014-07-15 15:33:07 -07002140 if (isValidLevel(level))
2141 {
2142 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04002143 gl::Error error = image->copyToStorage3D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002144 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002145 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002146 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002147 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002148
2149 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002150 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002151
2152 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002153}
2154
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002155gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2156{
2157 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2158 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2159}
Brandon Jones142ec422014-07-16 10:31:30 -07002160
Jamie Madillcb83dc12014-09-29 10:46:12 -04002161gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2162{
2163 // The "layer" here does not apply to 3D images. We use one Image per mip.
2164 return gl::ImageIndex::Make3D(mip);
2165}
2166
Brandon Jones142ec422014-07-16 10:31:30 -07002167TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002168 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002169{
2170 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2171 {
2172 mLayerCounts[level] = 0;
2173 mImageArray[level] = NULL;
2174 }
2175}
2176
2177TextureD3D_2DArray::~TextureD3D_2DArray()
2178{
Austin Kinross69822602014-08-12 15:51:37 -07002179 // Delete the Images before the TextureStorage.
2180 // Images might be relying on the TextureStorage for some of their data.
2181 // 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 -07002182 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002183 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002184}
2185
Brandon Jones142ec422014-07-16 10:31:30 -07002186Image *TextureD3D_2DArray::getImage(int level, int layer) const
2187{
2188 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2189 ASSERT(layer < mLayerCounts[level]);
2190 return mImageArray[level][layer];
2191}
2192
Jamie Madillfeda4d22014-09-17 13:03:29 -04002193Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2194{
2195 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2196 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2197 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2198 return mImageArray[index.mipIndex][index.layerIndex];
2199}
2200
Brandon Jones142ec422014-07-16 10:31:30 -07002201GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2202{
2203 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2204 return mLayerCounts[level];
2205}
2206
Brandon Jones142ec422014-07-16 10:31:30 -07002207GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2208{
2209 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2210}
2211
2212GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2213{
2214 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2215}
2216
Brandon Jones142ec422014-07-16 10:31:30 -07002217GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2218{
2219 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2220}
2221
2222bool TextureD3D_2DArray::isDepth(GLint level) const
2223{
Geoff Lang5d601382014-07-22 15:14:06 -04002224 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002225}
2226
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002227gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2228 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2229 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002230{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002231 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2232
Geoff Lang5d601382014-07-22 15:14:06 -04002233 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2234
Brandon Jones142ec422014-07-16 10:31:30 -07002235 redefineImage(level, sizedInternalFormat, width, height, depth);
2236
Geoff Lang5d601382014-07-22 15:14:06 -04002237 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2238 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002239
2240 for (int i = 0; i < depth; i++)
2241 {
2242 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002243 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2244 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002245 if (error.isError())
2246 {
2247 return error;
2248 }
Brandon Jones142ec422014-07-16 10:31:30 -07002249 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002250
2251 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002252}
2253
Geoff Langb5348332014-09-02 13:16:34 -04002254gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2255 GLsizei width, GLsizei height, GLsizei depth,
2256 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002257{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002258 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2259
Brandon Jones142ec422014-07-16 10:31:30 -07002260 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2261 redefineImage(level, format, width, height, depth);
2262
Geoff Lang5d601382014-07-22 15:14:06 -04002263 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2264 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002265
2266 for (int i = 0; i < depth; i++)
2267 {
2268 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002269 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2270 if (error.isError())
2271 {
2272 return error;
2273 }
Brandon Jones142ec422014-07-16 10:31:30 -07002274 }
Geoff Langb5348332014-09-02 13:16:34 -04002275
2276 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002277}
2278
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002279gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2280 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2281 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002282{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002283 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2284
Geoff Lang5d601382014-07-22 15:14:06 -04002285 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2286 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002287
2288 for (int i = 0; i < depth; i++)
2289 {
2290 int layer = zoffset + i;
2291 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2292
Jamie Madillfeda4d22014-09-17 13:03:29 -04002293 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002294 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2295 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002296 if (error.isError())
2297 {
2298 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002299 }
2300 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002301
2302 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002303}
2304
Geoff Langb5348332014-09-02 13:16:34 -04002305gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2306 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2307 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002308{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002309 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2310
Geoff Lang5d601382014-07-22 15:14:06 -04002311 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2312 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002313
2314 for (int i = 0; i < depth; i++)
2315 {
2316 int layer = zoffset + i;
2317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2318
Geoff Langb5348332014-09-02 13:16:34 -04002319 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2320 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002321 {
Geoff Langb5348332014-09-02 13:16:34 -04002322 return error;
2323 }
2324
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002325 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2326 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2327 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002328 if (error.isError())
2329 {
2330 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002331 }
2332 }
Geoff Langb5348332014-09-02 13:16:34 -04002333
2334 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002335}
2336
Geoff Langef7b0162014-09-04 13:29:23 -04002337gl::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 -07002338{
2339 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002340 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002341}
2342
Geoff Langef7b0162014-09-04 13:29:23 -04002343gl::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 -07002344{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002345 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2346
Brandon Jones142ec422014-07-16 10:31:30 -07002347 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2348 // the current level we're copying to is defined (with appropriate format, width & height)
2349 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2350
Jamie Madill82bf0c52014-10-03 11:50:53 -04002351 gl::Rectangle sourceRect(x, y, width, height);
2352
Brandon Jones142ec422014-07-16 10:31:30 -07002353 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2354 {
Geoff Langef7b0162014-09-04 13:29:23 -04002355 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2356 if (error.isError())
2357 {
2358 return error;
2359 }
2360
Brandon Jones142ec422014-07-16 10:31:30 -07002361 mDirtyImages = true;
2362 }
2363 else
2364 {
Geoff Langef7b0162014-09-04 13:29:23 -04002365 gl::Error error = ensureRenderTarget();
2366 if (error.isError())
2367 {
2368 return error;
2369 }
Brandon Jones142ec422014-07-16 10:31:30 -07002370
2371 if (isValidLevel(level))
2372 {
Geoff Langef7b0162014-09-04 13:29:23 -04002373 error = updateStorageLevel(level);
2374 if (error.isError())
2375 {
2376 return error;
2377 }
Brandon Jones142ec422014-07-16 10:31:30 -07002378
Geoff Langef7b0162014-09-04 13:29:23 -04002379 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2380 xoffset, yoffset, zoffset, mTexStorage, level);
2381 if (error.isError())
2382 {
2383 return error;
2384 }
Brandon Jones142ec422014-07-16 10:31:30 -07002385 }
2386 }
Geoff Langef7b0162014-09-04 13:29:23 -04002387 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002388}
2389
Geoff Lang1f8532b2014-09-05 09:46:13 -04002390gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002391{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002392 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2393
Brandon Jones142ec422014-07-16 10:31:30 -07002394 deleteImages();
2395
2396 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2397 {
2398 GLsizei levelWidth = std::max(1, width >> level);
2399 GLsizei levelHeight = std::max(1, height >> level);
2400
2401 mLayerCounts[level] = (level < levels ? depth : 0);
2402
2403 if (mLayerCounts[level] > 0)
2404 {
2405 // Create new images for this level
2406 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2407
2408 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2409 {
2410 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2411 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2412 levelHeight, 1, true);
2413 }
2414 }
2415 }
2416
Geoff Lang1f8532b2014-09-05 09:46:13 -04002417 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002418 bool renderTarget = IsRenderTargetUsage(mUsage);
2419 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002420
2421 gl::Error error = setCompleteTexStorage(storage);
2422 if (error.isError())
2423 {
2424 SafeDelete(storage);
2425 return error;
2426 }
2427
2428 mImmutable = true;
2429
2430 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002431}
2432
Brandon Jones6053a522014-07-25 16:22:09 -07002433void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002434{
Brandon Jones6053a522014-07-25 16:22:09 -07002435 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002436}
2437
Brandon Jones6053a522014-07-25 16:22:09 -07002438void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002439{
Brandon Jones6053a522014-07-25 16:22:09 -07002440 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002441}
2442
Brandon Jones6053a522014-07-25 16:22:09 -07002443
Jamie Madill4aa79e12014-09-29 10:46:14 -04002444void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002445{
2446 int baseWidth = getBaseLevelWidth();
2447 int baseHeight = getBaseLevelHeight();
2448 int baseDepth = getBaseLevelDepth();
2449 GLenum baseFormat = getBaseLevelInternalFormat();
2450
2451 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2452 int levelCount = mipLevels();
2453 for (int level = 1; level < levelCount; level++)
2454 {
2455 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2456 }
Brandon Jones142ec422014-07-16 10:31:30 -07002457}
2458
Jamie Madillac7579c2014-09-17 16:59:33 -04002459unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002460{
Geoff Langef7b0162014-09-04 13:29:23 -04002461 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002462}
2463
Jamie Madillac7579c2014-09-17 16:59:33 -04002464RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002465{
2466 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002467 gl::Error error = ensureRenderTarget();
2468 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002469 {
2470 return NULL;
2471 }
2472
Geoff Langef7b0162014-09-04 13:29:23 -04002473 error = updateStorageLevel(index.mipIndex);
2474 if (error.isError())
2475 {
2476 return NULL;
2477 }
2478
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002479 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002480}
2481
Geoff Langef7b0162014-09-04 13:29:23 -04002482gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002483{
2484 // Only initialize the first time this texture is used as a render target or shader resource
2485 if (mTexStorage)
2486 {
Geoff Langef7b0162014-09-04 13:29:23 -04002487 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002488 }
2489
2490 // do not attempt to create storage for nonexistant data
2491 if (!isLevelComplete(0))
2492 {
Geoff Langef7b0162014-09-04 13:29:23 -04002493 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002494 }
2495
2496 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2497
Geoff Langef7b0162014-09-04 13:29:23 -04002498 TextureStorage *storage = NULL;
2499 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2500 if (error.isError())
2501 {
2502 return error;
2503 }
2504
2505 error = setCompleteTexStorage(storage);
2506 if (error.isError())
2507 {
2508 SafeDelete(storage);
2509 return error;
2510 }
2511
Brandon Jones142ec422014-07-16 10:31:30 -07002512 ASSERT(mTexStorage);
2513
2514 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002515 error = updateStorage();
2516 if (error.isError())
2517 {
2518 return error;
2519 }
2520
2521 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002522}
2523
Geoff Langef7b0162014-09-04 13:29:23 -04002524gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002525{
2526 GLsizei width = getBaseLevelWidth();
2527 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002528 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002529 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002530
2531 ASSERT(width > 0 && height > 0 && depth > 0);
2532
2533 // use existing storage level count, when previously specified by TexStorage*D
2534 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2535
Geoff Langef7b0162014-09-04 13:29:23 -04002536 // TODO(geofflang): Verify storage creation succeeds
2537 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2538
2539 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002540}
2541
Geoff Langef7b0162014-09-04 13:29:23 -04002542gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002543{
2544 SafeDelete(mTexStorage);
2545 mTexStorage = newCompleteTexStorage;
2546 mDirtyImages = true;
2547
2548 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2549 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002550
2551 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002552}
2553
Geoff Langef7b0162014-09-04 13:29:23 -04002554gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002555{
2556 ASSERT(mTexStorage != NULL);
2557 GLint storageLevels = mTexStorage->getLevelCount();
2558 for (int level = 0; level < storageLevels; level++)
2559 {
2560 if (isLevelComplete(level))
2561 {
Geoff Langef7b0162014-09-04 13:29:23 -04002562 gl::Error error = updateStorageLevel(level);
2563 if (error.isError())
2564 {
2565 return error;
2566 }
Brandon Jones142ec422014-07-16 10:31:30 -07002567 }
2568 }
Geoff Langef7b0162014-09-04 13:29:23 -04002569
2570 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002571}
2572
Brandon Jones142ec422014-07-16 10:31:30 -07002573bool TextureD3D_2DArray::isValidLevel(int level) const
2574{
2575 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2576}
2577
2578bool TextureD3D_2DArray::isLevelComplete(int level) const
2579{
2580 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2581
2582 if (isImmutable())
2583 {
2584 return true;
2585 }
2586
2587 GLsizei width = getBaseLevelWidth();
2588 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002589 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002590
2591 if (width <= 0 || height <= 0 || layers <= 0)
2592 {
2593 return false;
2594 }
2595
2596 if (level == 0)
2597 {
2598 return true;
2599 }
2600
2601 if (getInternalFormat(level) != getInternalFormat(0))
2602 {
2603 return false;
2604 }
2605
2606 if (getWidth(level) != std::max(1, width >> level))
2607 {
2608 return false;
2609 }
2610
2611 if (getHeight(level) != std::max(1, height >> level))
2612 {
2613 return false;
2614 }
2615
Jamie Madill3269bcb2014-09-30 16:33:52 -04002616 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002617 {
2618 return false;
2619 }
2620
2621 return true;
2622}
2623
Geoff Langef7b0162014-09-04 13:29:23 -04002624gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002625{
2626 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2627 ASSERT(isLevelComplete(level));
2628
2629 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2630 {
2631 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2632 if (mImageArray[level][layer]->isDirty())
2633 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002634 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2635 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002636 gl::Error error = commitRegion(index, region);
2637 if (error.isError())
2638 {
2639 return error;
2640 }
Brandon Jones142ec422014-07-16 10:31:30 -07002641 }
2642 }
Geoff Langef7b0162014-09-04 13:29:23 -04002643
2644 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002645}
2646
2647void TextureD3D_2DArray::deleteImages()
2648{
2649 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2650 {
2651 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2652 {
2653 delete mImageArray[level][layer];
2654 }
2655 delete[] mImageArray[level];
2656 mImageArray[level] = NULL;
2657 mLayerCounts[level] = 0;
2658 }
2659}
2660
2661void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2662{
2663 // If there currently is a corresponding storage texture image, it has these parameters
2664 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2665 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002666 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002667 const GLenum storageFormat = getBaseLevelInternalFormat();
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] = depth;
2676
2677 if (depth > 0)
2678 {
2679 mImageArray[level] = new ImageD3D*[depth]();
2680
2681 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2682 {
2683 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2684 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2685 }
2686 }
2687
2688 if (mTexStorage)
2689 {
2690 const int storageLevels = mTexStorage->getLevelCount();
2691
2692 if ((level >= storageLevels && storageLevels != 0) ||
2693 width != storageWidth ||
2694 height != storageHeight ||
2695 depth != storageDepth ||
2696 internalformat != storageFormat) // Discard mismatched storage
2697 {
2698 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2699 {
2700 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2701 {
2702 mImageArray[level][layer]->markDirty();
2703 }
2704 }
2705
2706 delete mTexStorage;
2707 mTexStorage = NULL;
2708 mDirtyImages = true;
2709 }
2710 }
2711}
2712
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002713gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002714{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002715 ASSERT(index.hasLayer());
2716 GLint level = index.mipIndex;
2717 GLint layerTarget = index.layerIndex;
2718
Jamie Madill3269bcb2014-09-30 16:33:52 -04002719 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002720 {
2721 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04002722 gl::Error error = image->copyToStorage2DArray(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002723 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002724 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002725 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002726 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002727
2728 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002729 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002730
2731 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002732}
2733
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002734gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2735{
2736 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2737}
2738
Jamie Madillcb83dc12014-09-29 10:46:12 -04002739gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2740{
2741 return gl::ImageIndex::Make2DArray(mip, layer);
2742}
2743
Brandon Jones78b1acd2014-07-15 15:33:07 -07002744}