blob: a467238292ad599b726bb674eb91f547fab25f25 [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
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040093gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
95 // No-op
96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
97 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040098 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -070099 }
100
101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
103 const void *pixelData = pixels;
104
105 if (unpack.pixelBuffer.id() != 0)
106 {
107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
111 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
112 const void *bufferData = pixelBuffer->getImplementation()->getData();
113 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
114 }
115
116 if (pixelData != NULL)
117 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400118 gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 if (error.isError())
120 {
121 return error;
122 }
123
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 mDirtyImages = true;
125 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400126
127 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700128}
129
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400130gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
131 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700132{
Jamie Madill2d337ce2014-10-03 11:50:56 -0400133 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700134
135 // CPU readback & copy where direct GPU copy is not supported
136 if (unpack.pixelBuffer.id() != 0)
137 {
138 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200139 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700140 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
141 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
142 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill2d337ce2014-10-03 11:50:56 -0400143 pixelData = static_cast<const uint8_t *>(bufferData)+offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 }
145
146 if (pixelData != NULL)
147 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400148 Image *image = getImage(index);
149 ASSERT(image);
150
Jamie Madill2d337ce2014-10-03 11:50:56 -0400151 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
152 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
153
154 // TODO(jmadill): Handle compressed internal formats
155 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
156 {
157 return getNativeTexture()->setData(index, region, image->getInternalFormat(),
158 type, unpack, pixelData);
159 }
160
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400161 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
162 type, pixelData);
163 if (error.isError())
164 {
165 return error;
166 }
167
Jamie Madille6b6da02014-10-02 11:03:14 -0400168 error = commitRegion(index, region);
169 if (error.isError())
170 {
171 return error;
172 }
173
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174 mDirtyImages = true;
175 }
176
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400177 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700178}
179
Geoff Langb5348332014-09-02 13:16:34 -0400180gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181{
182 if (pixels != NULL)
183 {
Geoff Langb5348332014-09-02 13:16:34 -0400184 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
185 if (error.isError())
186 {
187 return error;
188 }
189
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700190 mDirtyImages = true;
191 }
Geoff Langb5348332014-09-02 13:16:34 -0400192
193 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194}
195
Geoff Langb5348332014-09-02 13:16:34 -0400196gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700197 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198{
199 if (pixels != NULL)
200 {
Geoff Langb5348332014-09-02 13:16:34 -0400201 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
202 if (error.isError())
203 {
204 return error;
205 }
206
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700207 mDirtyImages = true;
208 }
209
Geoff Langb5348332014-09-02 13:16:34 -0400210 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211}
212
213bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
214{
215 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
216}
217
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400218gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
219 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700220{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400221 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700222 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
223 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400224 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700225 }
226
227 // In order to perform the fast copy through the shader, we must have the right format, and be able
228 // to create a render target.
229 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
230
Jacek Cabana5521de2014-10-01 17:23:46 +0200231 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700232
Geoff Langae5122c2014-08-27 14:08:43 -0400233 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
234 if (error.isError())
235 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400236 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400237 }
238
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400239 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240}
241
242GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
243{
244 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
245 {
246 // Maximum number of levels
247 return gl::log2(std::max(std::max(width, height), depth)) + 1;
248 }
249 else
250 {
251 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
252 return 1;
253 }
254}
255
256int TextureD3D::mipLevels() const
257{
258 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
259}
260
Jamie Madill98553e32014-09-30 16:33:50 -0400261TextureStorage *TextureD3D::getStorage()
262{
263 return mTexStorage;
264}
265
Jamie Madill3269bcb2014-09-30 16:33:52 -0400266Image *TextureD3D::getBaseLevelImage() const
267{
268 return getImage(getImageIndex(0, 0));
269}
270
Jamie Madill4aa79e12014-09-29 10:46:14 -0400271void TextureD3D::generateMipmaps()
272{
Jamie Madill2d337ce2014-10-03 11:50:56 -0400273 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400274 initMipmapsImages();
275
276 // We know that all layers have the same dimension, for the texture to be complete
277 GLint layerCount = static_cast<GLint>(getLayerCount(0));
278 GLint mipCount = mipLevels();
279
Jamie Madill2d337ce2014-10-03 11:50:56 -0400280 // When making mipmaps with the setData workaround enabled, the texture storage has
281 // the image data already. For non-render-target storage, we have to pull it out into
282 // an image layer.
283 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
284 {
285 if (!mTexStorage->isRenderTarget())
286 {
287 // Copy from the storage mip 0 to Image mip 0
288 for (GLint layer = 0; layer < layerCount; ++layer)
289 {
290 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400291
Jamie Madill2d337ce2014-10-03 11:50:56 -0400292 Image *image = getImage(srcIndex);
293 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
294 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
295 }
296 }
297 else
298 {
299 updateStorage();
300 }
301 }
302
303 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400304
305 for (GLint layer = 0; layer < layerCount; ++layer)
306 {
307 for (GLint mip = 1; mip < mipCount; ++mip)
308 {
309 ASSERT(getLayerCount(mip) == layerCount);
310
311 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
312 gl::ImageIndex destIndex = getImageIndex(mip, layer);
313
314 if (renderableStorage)
315 {
316 // GPU-side mipmapping
Jamie Madill2d337ce2014-10-03 11:50:56 -0400317 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400318 }
319 else
320 {
321 // CPU-side mipmapping
322 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
323 }
324 }
325 }
326}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700327
Jamie Madill135570a2014-09-30 16:33:51 -0400328bool TextureD3D::isBaseImageZeroSize() const
329{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400330 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400331
332 if (!baseImage || baseImage->getWidth() <= 0)
333 {
334 return true;
335 }
336
337 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
338 {
339 return true;
340 }
341
342 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
343 {
344 return true;
345 }
346
347 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
348 {
349 return true;
350 }
351
352 return false;
353}
354
355bool TextureD3D::ensureRenderTarget()
356{
357 initializeStorage(true);
358
359 if (!isBaseImageZeroSize())
360 {
361 ASSERT(mTexStorage);
362 if (!mTexStorage->isRenderTarget())
363 {
364 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
365
366 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
367 {
368 delete newRenderTargetStorage;
369 return gl::error(GL_OUT_OF_MEMORY, false);
370 }
371
372 setCompleteTexStorage(newRenderTargetStorage);
373 }
374 }
375
376 return (mTexStorage && mTexStorage->isRenderTarget());
377}
378
Brandon Jones78b1acd2014-07-15 15:33:07 -0700379TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400380 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700381{
382 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
383 {
384 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
385 }
386}
387
388TextureD3D_2D::~TextureD3D_2D()
389{
Austin Kinross69822602014-08-12 15:51:37 -0700390 // Delete the Images before the TextureStorage.
391 // Images might be relying on the TextureStorage for some of their data.
392 // 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 -0700393 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
394 {
395 delete mImageArray[i];
396 }
Austin Kinross69822602014-08-12 15:51:37 -0700397
398 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700399}
400
Brandon Jonescef06ff2014-08-05 13:27:48 -0700401Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700402{
403 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700404 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700405 return mImageArray[level];
406}
407
Jamie Madillfeda4d22014-09-17 13:03:29 -0400408Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
409{
410 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400411 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400412 ASSERT(index.type == GL_TEXTURE_2D);
413 return mImageArray[index.mipIndex];
414}
415
Brandon Jonescef06ff2014-08-05 13:27:48 -0700416GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700417{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700418 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
419 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700420}
421
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700422GLsizei TextureD3D_2D::getWidth(GLint level) const
423{
424 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
425 return mImageArray[level]->getWidth();
426 else
427 return 0;
428}
429
430GLsizei TextureD3D_2D::getHeight(GLint level) const
431{
432 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
433 return mImageArray[level]->getHeight();
434 else
435 return 0;
436}
437
438GLenum TextureD3D_2D::getInternalFormat(GLint level) const
439{
440 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
441 return mImageArray[level]->getInternalFormat();
442 else
443 return GL_NONE;
444}
445
446GLenum TextureD3D_2D::getActualFormat(GLint level) const
447{
448 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
449 return mImageArray[level]->getActualFormat();
450 else
451 return GL_NONE;
452}
453
454bool TextureD3D_2D::isDepth(GLint level) const
455{
Geoff Lang5d601382014-07-22 15:14:06 -0400456 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700457}
458
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400459gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
460 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
461 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700462{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700463 ASSERT(target == GL_TEXTURE_2D && depth == 1);
464
Geoff Lang5d601382014-07-22 15:14:06 -0400465 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
466
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700467 bool fastUnpacked = false;
468
Brandon Jonescef06ff2014-08-05 13:27:48 -0700469 redefineImage(level, sizedInternalFormat, width, height);
470
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700471 // Attempt a fast gpu copy of the pixel data to the surface
472 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
473 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400474 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
475
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700476 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400477 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700478 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
479
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400480 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400482 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
483 if (error.isError())
484 {
485 return error;
486 }
487
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700488 // Ensure we don't overwrite our newly initialized data
489 mImageArray[level]->markClean();
490
491 fastUnpacked = true;
492 }
493 }
494
495 if (!fastUnpacked)
496 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400497 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
498 if (error.isError())
499 {
500 return error;
501 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700502 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400503
504 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505}
506
Geoff Langb5348332014-09-02 13:16:34 -0400507gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
508 GLsizei width, GLsizei height, GLsizei depth,
509 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700510{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700511 ASSERT(target == GL_TEXTURE_2D && depth == 1);
512
513 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
514 redefineImage(level, format, width, height);
515
Geoff Langb5348332014-09-02 13:16:34 -0400516 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700517}
518
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400519gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
520 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
521 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700523 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
524
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700525 bool fastUnpacked = false;
526
Jamie Madillac7579c2014-09-17 16:59:33 -0400527 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400528 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700529 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
530 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400531 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700532
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400533 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400535 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
536 if (error.isError())
537 {
538 return error;
539 }
540
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700541 // Ensure we don't overwrite our newly initialized data
542 mImageArray[level]->markClean();
543
544 fastUnpacked = true;
545 }
546 }
547
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400548 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700549 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400550 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
551 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400553
554 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555}
556
Geoff Langb5348332014-09-02 13:16:34 -0400557gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
558 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
559 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700561 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
562
Geoff Langb5348332014-09-02 13:16:34 -0400563 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
564 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700565 {
Geoff Langb5348332014-09-02 13:16:34 -0400566 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567 }
Geoff Langb5348332014-09-02 13:16:34 -0400568
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400569 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
570 gl::Box region(xoffset, yoffset, 0, width, height, 1);
571 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700572}
573
Brandon Jonescef06ff2014-08-05 13:27:48 -0700574void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700576 ASSERT(target == GL_TEXTURE_2D);
577
578 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
579 redefineImage(level, sizedInternalFormat, width, height);
580
Jamie Madill82bf0c52014-10-03 11:50:53 -0400581 gl::Rectangle sourceRect(x, y, width, height);
582
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583 if (!mImageArray[level]->isRenderableFormat())
584 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400585 mImageArray[level]->copy(0, 0, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586 mDirtyImages = true;
587 }
588 else
589 {
590 ensureRenderTarget();
591 mImageArray[level]->markClean();
592
593 if (width != 0 && height != 0 && isValidLevel(level))
594 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400595 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596 }
597 }
598}
599
600void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
601{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700602 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
603
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
605 // the current level we're copying to is defined (with appropriate format, width & height)
606 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
607
Jamie Madill82bf0c52014-10-03 11:50:53 -0400608 gl::Rectangle sourceRect(x, y, width, height);
609
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
611 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400612 mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 mDirtyImages = true;
614 }
615 else
616 {
617 ensureRenderTarget();
618
619 if (isValidLevel(level))
620 {
621 updateStorageLevel(level);
622
Jamie Madill856d9d42014-09-18 15:08:49 -0400623 mRenderer->copyImage2D(source, sourceRect,
624 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
625 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626 }
627 }
628}
629
Brandon Jonescef06ff2014-08-05 13:27:48 -0700630void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700632 ASSERT(target == GL_TEXTURE_2D && depth == 1);
633
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634 for (int level = 0; level < levels; level++)
635 {
636 GLsizei levelWidth = std::max(1, width >> level);
637 GLsizei levelHeight = std::max(1, height >> level);
638 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
639 }
640
641 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
642 {
643 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
644 }
645
646 mImmutable = true;
647
Jamie Madillc4833262014-09-18 16:18:26 -0400648 bool renderTarget = IsRenderTargetUsage(mUsage);
649 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400650 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651}
652
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700653void TextureD3D_2D::bindTexImage(egl::Surface *surface)
654{
655 GLenum internalformat = surface->getFormat();
656
657 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
658
659 if (mTexStorage)
660 {
661 SafeDelete(mTexStorage);
662 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400663
664 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665
666 mDirtyImages = true;
667}
668
669void TextureD3D_2D::releaseTexImage()
670{
671 if (mTexStorage)
672 {
673 SafeDelete(mTexStorage);
674 }
675
676 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
677 {
678 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
679 }
680}
681
Jamie Madill4aa79e12014-09-29 10:46:14 -0400682void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700684 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700685 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700686 for (int level = 1; level < levelCount; level++)
687 {
688 redefineImage(level, getBaseLevelInternalFormat(),
689 std::max(getBaseLevelWidth() >> level, 1),
690 std::max(getBaseLevelHeight() >> level, 1));
691 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700692}
693
Jamie Madillac7579c2014-09-17 16:59:33 -0400694unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700695{
Jamie Madillac7579c2014-09-17 16:59:33 -0400696 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400697 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700698}
699
Jamie Madillac7579c2014-09-17 16:59:33 -0400700RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700701{
Jamie Madillac7579c2014-09-17 16:59:33 -0400702 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700703
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704 // ensure the underlying texture is created
705 if (!ensureRenderTarget())
706 {
707 return NULL;
708 }
709
Jamie Madillac7579c2014-09-17 16:59:33 -0400710 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400711 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712}
713
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700714bool TextureD3D_2D::isValidLevel(int level) const
715{
716 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
717}
718
719bool TextureD3D_2D::isLevelComplete(int level) const
720{
721 if (isImmutable())
722 {
723 return true;
724 }
725
Brandon Jones78b1acd2014-07-15 15:33:07 -0700726 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700727
728 GLsizei width = baseImage->getWidth();
729 GLsizei height = baseImage->getHeight();
730
731 if (width <= 0 || height <= 0)
732 {
733 return false;
734 }
735
736 // The base image level is complete if the width and height are positive
737 if (level == 0)
738 {
739 return true;
740 }
741
742 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700743 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744
745 if (image->getInternalFormat() != baseImage->getInternalFormat())
746 {
747 return false;
748 }
749
750 if (image->getWidth() != std::max(1, width >> level))
751 {
752 return false;
753 }
754
755 if (image->getHeight() != std::max(1, height >> level))
756 {
757 return false;
758 }
759
760 return true;
761}
762
763// Constructs a native texture resource from the texture images
764void TextureD3D_2D::initializeStorage(bool renderTarget)
765{
766 // Only initialize the first time this texture is used as a render target or shader resource
767 if (mTexStorage)
768 {
769 return;
770 }
771
772 // do not attempt to create storage for nonexistant data
773 if (!isLevelComplete(0))
774 {
775 return;
776 }
777
778 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
779
780 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
781 ASSERT(mTexStorage);
782
783 // flush image data to the storage
784 updateStorage();
785}
786
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400787TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700788{
789 GLsizei width = getBaseLevelWidth();
790 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400791 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700792
793 ASSERT(width > 0 && height > 0);
794
795 // use existing storage level count, when previously specified by TexStorage*D
796 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
797
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400798 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700799}
800
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400801void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700802{
803 SafeDelete(mTexStorage);
804 mTexStorage = newCompleteTexStorage;
805
806 if (mTexStorage && mTexStorage->isManaged())
807 {
808 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
809 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400810 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700811 }
812 }
813
814 mDirtyImages = true;
815}
816
817void TextureD3D_2D::updateStorage()
818{
819 ASSERT(mTexStorage != NULL);
820 GLint storageLevels = mTexStorage->getLevelCount();
821 for (int level = 0; level < storageLevels; level++)
822 {
823 if (mImageArray[level]->isDirty() && isLevelComplete(level))
824 {
825 updateStorageLevel(level);
826 }
827 }
828}
829
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700830void TextureD3D_2D::updateStorageLevel(int level)
831{
832 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
833 ASSERT(isLevelComplete(level));
834
835 if (mImageArray[level]->isDirty())
836 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400837 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
838 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
839 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700840 }
841}
842
843void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
844{
845 // If there currently is a corresponding storage texture image, it has these parameters
846 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
847 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
848 const GLenum storageFormat = getBaseLevelInternalFormat();
849
850 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
851
852 if (mTexStorage)
853 {
854 const int storageLevels = mTexStorage->getLevelCount();
855
856 if ((level >= storageLevels && storageLevels != 0) ||
857 width != storageWidth ||
858 height != storageHeight ||
859 internalformat != storageFormat) // Discard mismatched storage
860 {
861 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
862 {
863 mImageArray[i]->markDirty();
864 }
865
866 SafeDelete(mTexStorage);
867 mDirtyImages = true;
868 }
869 }
870}
871
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400872gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700873{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400874 ASSERT(!index.hasLayer());
875 GLint level = index.mipIndex;
876
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700877 if (isValidLevel(level))
878 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700879 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400880 gl::Error error = image->copyToStorage2D(mTexStorage, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400881 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400883 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700884 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400885
886 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700887 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400888
889 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700890}
891
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400892gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
893{
894 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
895}
Brandon Jones0511e802014-07-14 16:27:26 -0700896
Jamie Madillcb83dc12014-09-29 10:46:12 -0400897gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
898{
899 // "layer" does not apply to 2D Textures.
900 return gl::ImageIndex::Make2D(mip);
901}
902
Brandon Jones78b1acd2014-07-15 15:33:07 -0700903TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400904 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700905{
906 for (int i = 0; i < 6; i++)
907 {
908 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
909 {
910 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
911 }
912 }
913}
914
915TextureD3D_Cube::~TextureD3D_Cube()
916{
Austin Kinross69822602014-08-12 15:51:37 -0700917 // Delete the Images before the TextureStorage.
918 // Images might be relying on the TextureStorage for some of their data.
919 // 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 -0700920 for (int i = 0; i < 6; i++)
921 {
922 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
923 {
924 SafeDelete(mImageArray[i][j]);
925 }
926 }
Austin Kinross69822602014-08-12 15:51:37 -0700927
928 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700929}
930
Brandon Jonescef06ff2014-08-05 13:27:48 -0700931Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700932{
933 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700934 ASSERT(layer < 6);
935 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700936}
937
Jamie Madillfeda4d22014-09-17 13:03:29 -0400938Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
939{
940 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
941 ASSERT(index.layerIndex < 6);
942 return mImageArray[index.layerIndex][index.mipIndex];
943}
944
Brandon Jonescef06ff2014-08-05 13:27:48 -0700945GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700946{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700947 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
948 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700949}
950
Brandon Jonescef06ff2014-08-05 13:27:48 -0700951GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700952{
953 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700954 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700955 else
956 return GL_NONE;
957}
958
Brandon Jonescef06ff2014-08-05 13:27:48 -0700959bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700960{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700961 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700962}
963
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400964gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
965 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
966 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700967{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700968 ASSERT(depth == 1);
969
970 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400971 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700972
973 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
974
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400975 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700976}
977
Geoff Langb5348332014-09-02 13:16:34 -0400978gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
979 GLsizei width, GLsizei height, GLsizei depth,
980 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700981{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700982 ASSERT(depth == 1);
983
Brandon Jones0511e802014-07-14 16:27:26 -0700984 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700985 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
986
Brandon Jones0511e802014-07-14 16:27:26 -0700987 redefineImage(faceIndex, level, format, width, height);
988
Geoff Langb5348332014-09-02 13:16:34 -0400989 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700990}
991
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400992gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
993 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
994 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700995{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700996 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400997 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -0400998 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -0700999}
1000
Geoff Langb5348332014-09-02 13:16:34 -04001001gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1002 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1003 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001004{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001005 ASSERT(depth == 1 && zoffset == 0);
1006
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001007 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001008
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001009 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 -04001010 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001011 {
Geoff Langb5348332014-09-02 13:16:34 -04001012 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001013 }
Geoff Langb5348332014-09-02 13:16:34 -04001014
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001015 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1016 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001017}
1018
1019void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1020{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001021 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001022 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1023
Brandon Jones0511e802014-07-14 16:27:26 -07001024 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1025
Jamie Madill82bf0c52014-10-03 11:50:53 -04001026 gl::Rectangle sourceRect(x, y, width, height);
1027
Brandon Jones0511e802014-07-14 16:27:26 -07001028 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1029 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001030 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001031 mDirtyImages = true;
1032 }
1033 else
1034 {
1035 ensureRenderTarget();
1036 mImageArray[faceIndex][level]->markClean();
1037
1038 ASSERT(width == height);
1039
1040 if (width > 0 && isValidFaceLevel(faceIndex, level))
1041 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001042 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001043 }
1044 }
1045}
1046
1047void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1048{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001049 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001050
1051 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1052 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1053 // rely on the "getBaseLevel*" methods reliably otherwise.
1054 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1055
Jamie Madill82bf0c52014-10-03 11:50:53 -04001056 gl::Rectangle sourceRect(x, y, width, height);
1057
Brandon Jones0511e802014-07-14 16:27:26 -07001058 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1059 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001060 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001061 mDirtyImages = true;
1062 }
1063 else
1064 {
1065 ensureRenderTarget();
1066
1067 if (isValidFaceLevel(faceIndex, level))
1068 {
1069 updateStorageFaceLevel(faceIndex, level);
1070
Jamie Madill856d9d42014-09-18 15:08:49 -04001071 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1072 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001073 }
1074 }
1075}
1076
Brandon Jonescef06ff2014-08-05 13:27:48 -07001077void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001078{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001079 ASSERT(width == height);
1080 ASSERT(depth == 1);
1081
Brandon Jones0511e802014-07-14 16:27:26 -07001082 for (int level = 0; level < levels; level++)
1083 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001084 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001085 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1086 {
1087 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1088 }
1089 }
1090
1091 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1092 {
1093 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1094 {
1095 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1096 }
1097 }
1098
1099 mImmutable = true;
1100
Jamie Madillc4833262014-09-18 16:18:26 -04001101 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001102 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1103 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001104}
1105
Brandon Jones0511e802014-07-14 16:27:26 -07001106// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1107bool TextureD3D_Cube::isCubeComplete() const
1108{
1109 int baseWidth = getBaseLevelWidth();
1110 int baseHeight = getBaseLevelHeight();
1111 GLenum baseFormat = getBaseLevelInternalFormat();
1112
1113 if (baseWidth <= 0 || baseWidth != baseHeight)
1114 {
1115 return false;
1116 }
1117
1118 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1119 {
1120 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1121
1122 if (faceBaseImage.getWidth() != baseWidth ||
1123 faceBaseImage.getHeight() != baseHeight ||
1124 faceBaseImage.getInternalFormat() != baseFormat )
1125 {
1126 return false;
1127 }
1128 }
1129
1130 return true;
1131}
1132
Brandon Jones6053a522014-07-25 16:22:09 -07001133void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1134{
1135 UNREACHABLE();
1136}
1137
1138void TextureD3D_Cube::releaseTexImage()
1139{
1140 UNREACHABLE();
1141}
1142
1143
Jamie Madill4aa79e12014-09-29 10:46:14 -04001144void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001145{
1146 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1147 int levelCount = mipLevels();
1148 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1149 {
1150 for (int level = 1; level < levelCount; level++)
1151 {
1152 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1153 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1154 }
1155 }
Brandon Jones0511e802014-07-14 16:27:26 -07001156}
1157
Jamie Madillac7579c2014-09-17 16:59:33 -04001158unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001159{
Jamie Madillc4833262014-09-18 16:18:26 -04001160 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001161}
1162
Jamie Madillac7579c2014-09-17 16:59:33 -04001163RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001164{
Jamie Madillac7579c2014-09-17 16:59:33 -04001165 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001166
1167 // ensure the underlying texture is created
1168 if (!ensureRenderTarget())
1169 {
1170 return NULL;
1171 }
1172
Jamie Madillac7579c2014-09-17 16:59:33 -04001173 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001174 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001175}
1176
Brandon Jones0511e802014-07-14 16:27:26 -07001177void TextureD3D_Cube::initializeStorage(bool renderTarget)
1178{
1179 // Only initialize the first time this texture is used as a render target or shader resource
1180 if (mTexStorage)
1181 {
1182 return;
1183 }
1184
1185 // do not attempt to create storage for nonexistant data
1186 if (!isFaceLevelComplete(0, 0))
1187 {
1188 return;
1189 }
1190
1191 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1192
1193 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1194 ASSERT(mTexStorage);
1195
1196 // flush image data to the storage
1197 updateStorage();
1198}
1199
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001200TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001201{
1202 GLsizei size = getBaseLevelWidth();
1203
1204 ASSERT(size > 0);
1205
1206 // use existing storage level count, when previously specified by TexStorage*D
1207 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1208
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001209 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001210}
1211
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001212void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001213{
1214 SafeDelete(mTexStorage);
1215 mTexStorage = newCompleteTexStorage;
1216
1217 if (mTexStorage && mTexStorage->isManaged())
1218 {
1219 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1220 {
1221 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1222 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001223 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001224 }
1225 }
1226 }
1227
1228 mDirtyImages = true;
1229}
1230
1231void TextureD3D_Cube::updateStorage()
1232{
1233 ASSERT(mTexStorage != NULL);
1234 GLint storageLevels = mTexStorage->getLevelCount();
1235 for (int face = 0; face < 6; face++)
1236 {
1237 for (int level = 0; level < storageLevels; level++)
1238 {
1239 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1240 {
1241 updateStorageFaceLevel(face, level);
1242 }
1243 }
1244 }
1245}
1246
Brandon Jones0511e802014-07-14 16:27:26 -07001247bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1248{
1249 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1250}
1251
Brandon Jones0511e802014-07-14 16:27:26 -07001252bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1253{
1254 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1255
1256 if (isImmutable())
1257 {
1258 return true;
1259 }
1260
1261 int baseSize = getBaseLevelWidth();
1262
1263 if (baseSize <= 0)
1264 {
1265 return false;
1266 }
1267
1268 // "isCubeComplete" checks for base level completeness and we must call that
1269 // to determine if any face at level 0 is complete. We omit that check here
1270 // to avoid re-checking cube-completeness for every face at level 0.
1271 if (level == 0)
1272 {
1273 return true;
1274 }
1275
1276 // Check that non-zero levels are consistent with the base level.
1277 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1278
1279 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1280 {
1281 return false;
1282 }
1283
1284 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1285 {
1286 return false;
1287 }
1288
1289 return true;
1290}
1291
1292void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1293{
1294 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1295 ImageD3D *image = mImageArray[faceIndex][level];
1296
1297 if (image->isDirty())
1298 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001299 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1300 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1301 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1302 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001303 }
1304}
1305
1306void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1307{
1308 // If there currently is a corresponding storage texture image, it has these parameters
1309 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1310 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1311 const GLenum storageFormat = getBaseLevelInternalFormat();
1312
1313 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1314
1315 if (mTexStorage)
1316 {
1317 const int storageLevels = mTexStorage->getLevelCount();
1318
1319 if ((level >= storageLevels && storageLevels != 0) ||
1320 width != storageWidth ||
1321 height != storageHeight ||
1322 internalformat != storageFormat) // Discard mismatched storage
1323 {
1324 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1325 {
1326 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1327 {
1328 mImageArray[faceIndex][level]->markDirty();
1329 }
1330 }
1331
1332 SafeDelete(mTexStorage);
1333
1334 mDirtyImages = true;
1335 }
1336 }
1337}
1338
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001339gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001340{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001341 ASSERT(index.hasLayer());
1342
1343 GLint level = index.mipIndex;
1344 int faceIndex = static_cast<int>(index.layerIndex);
1345
Brandon Jones0511e802014-07-14 16:27:26 -07001346 if (isValidFaceLevel(faceIndex, level))
1347 {
1348 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001349 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001350 if (error.isError())
1351 {
1352 return error;
1353 }
1354
1355 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001356 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001357
1358 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001359}
1360
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001361gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1362{
1363 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1364}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001365
Jamie Madillcb83dc12014-09-29 10:46:12 -04001366gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1367{
1368 // The "layer" of the image index corresponds to the cube face
1369 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1370}
1371
Brandon Jones78b1acd2014-07-15 15:33:07 -07001372TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001373 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001374{
1375 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1376 {
1377 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1378 }
1379}
1380
1381TextureD3D_3D::~TextureD3D_3D()
1382{
Austin Kinross69822602014-08-12 15:51:37 -07001383 // Delete the Images before the TextureStorage.
1384 // Images might be relying on the TextureStorage for some of their data.
1385 // 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 -07001386 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1387 {
1388 delete mImageArray[i];
1389 }
Austin Kinross69822602014-08-12 15:51:37 -07001390
1391 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001392}
1393
Brandon Jonescef06ff2014-08-05 13:27:48 -07001394Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001395{
1396 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001397 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398 return mImageArray[level];
1399}
1400
Jamie Madillfeda4d22014-09-17 13:03:29 -04001401Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1402{
1403 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001404 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001405 ASSERT(index.type == GL_TEXTURE_3D);
1406 return mImageArray[index.mipIndex];
1407}
1408
Brandon Jonescef06ff2014-08-05 13:27:48 -07001409GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001410{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001411 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1412 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413}
1414
Brandon Jones78b1acd2014-07-15 15:33:07 -07001415GLsizei TextureD3D_3D::getWidth(GLint level) const
1416{
1417 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1418 return mImageArray[level]->getWidth();
1419 else
1420 return 0;
1421}
1422
1423GLsizei TextureD3D_3D::getHeight(GLint level) const
1424{
1425 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1426 return mImageArray[level]->getHeight();
1427 else
1428 return 0;
1429}
1430
1431GLsizei TextureD3D_3D::getDepth(GLint level) const
1432{
1433 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1434 return mImageArray[level]->getDepth();
1435 else
1436 return 0;
1437}
1438
1439GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1440{
1441 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1442 return mImageArray[level]->getInternalFormat();
1443 else
1444 return GL_NONE;
1445}
1446
1447bool TextureD3D_3D::isDepth(GLint level) const
1448{
Geoff Lang5d601382014-07-22 15:14:06 -04001449 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001450}
1451
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001452gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1453 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1454 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001455{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001456 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001457 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1458
Brandon Jones78b1acd2014-07-15 15:33:07 -07001459 redefineImage(level, sizedInternalFormat, width, height, depth);
1460
1461 bool fastUnpacked = false;
1462
1463 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1464 if (isFastUnpackable(unpack, sizedInternalFormat))
1465 {
1466 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001467 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1468 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001469 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1470
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001471 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001472 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001473 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1474 if (error.isError())
1475 {
1476 return error;
1477 }
1478
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479 // Ensure we don't overwrite our newly initialized data
1480 mImageArray[level]->markClean();
1481
1482 fastUnpacked = true;
1483 }
1484 }
1485
1486 if (!fastUnpacked)
1487 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001488 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1489 if (error.isError())
1490 {
1491 return error;
1492 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001493 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001494
1495 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001496}
1497
Geoff Langb5348332014-09-02 13:16:34 -04001498gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1499 GLsizei width, GLsizei height,GLsizei depth,
1500 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001501{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001502 ASSERT(target == GL_TEXTURE_3D);
1503
Brandon Jones78b1acd2014-07-15 15:33:07 -07001504 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1505 redefineImage(level, format, width, height, depth);
1506
Geoff Langb5348332014-09-02 13:16:34 -04001507 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001508}
1509
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001510gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1511 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1512 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001513{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001514 ASSERT(target == GL_TEXTURE_3D);
1515
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516 bool fastUnpacked = false;
1517
Jamie Madillac7579c2014-09-17 16:59:33 -04001518 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1519
Brandon Jones78b1acd2014-07-15 15:33:07 -07001520 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1521 if (isFastUnpackable(unpack, getInternalFormat(level)))
1522 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001523 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001524
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001525 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001526 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001527 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001528 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1529 if (error.isError())
1530 {
1531 return error;
1532 }
1533
Brandon Jones78b1acd2014-07-15 15:33:07 -07001534 // Ensure we don't overwrite our newly initialized data
1535 mImageArray[level]->markClean();
1536
1537 fastUnpacked = true;
1538 }
1539 }
1540
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001541 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001542 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001543 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1544 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001545 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001546
1547 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001548}
1549
Geoff Langb5348332014-09-02 13:16:34 -04001550gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1551 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1552 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001553{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001554 ASSERT(target == GL_TEXTURE_3D);
1555
Geoff Langb5348332014-09-02 13:16:34 -04001556 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1557 format, imageSize, pixels, mImageArray[level]);
1558 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001559 {
Geoff Langb5348332014-09-02 13:16:34 -04001560 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001561 }
Geoff Langb5348332014-09-02 13:16:34 -04001562
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001563 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1564 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1565 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001566}
1567
Brandon Jonescef06ff2014-08-05 13:27:48 -07001568void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1569{
1570 UNIMPLEMENTED();
1571}
1572
Brandon Jones78b1acd2014-07-15 15:33:07 -07001573void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1574{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001575 ASSERT(target == GL_TEXTURE_3D);
1576
Brandon Jones78b1acd2014-07-15 15:33:07 -07001577 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1578 // the current level we're copying to is defined (with appropriate format, width & height)
1579 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1580
Jamie Madill82bf0c52014-10-03 11:50:53 -04001581 gl::Rectangle sourceRect(x, y, width, height);
1582
Brandon Jones78b1acd2014-07-15 15:33:07 -07001583 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1584 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001585 mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001586 mDirtyImages = true;
1587 }
1588 else
1589 {
1590 ensureRenderTarget();
1591
1592 if (isValidLevel(level))
1593 {
1594 updateStorageLevel(level);
1595
Jamie Madill856d9d42014-09-18 15:08:49 -04001596 mRenderer->copyImage3D(source, sourceRect,
1597 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1598 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001599 }
1600 }
1601}
1602
Brandon Jonescef06ff2014-08-05 13:27:48 -07001603void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001604{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001605 ASSERT(target == GL_TEXTURE_3D);
1606
Brandon Jones78b1acd2014-07-15 15:33:07 -07001607 for (int level = 0; level < levels; level++)
1608 {
1609 GLsizei levelWidth = std::max(1, width >> level);
1610 GLsizei levelHeight = std::max(1, height >> level);
1611 GLsizei levelDepth = std::max(1, depth >> level);
1612 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1613 }
1614
1615 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1616 {
1617 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1618 }
1619
1620 mImmutable = true;
1621
Jamie Madillc4833262014-09-18 16:18:26 -04001622 bool renderTarget = IsRenderTargetUsage(mUsage);
1623 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001624 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001625}
1626
Brandon Jones6053a522014-07-25 16:22:09 -07001627void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001628{
Brandon Jones6053a522014-07-25 16:22:09 -07001629 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001630}
1631
Brandon Jones6053a522014-07-25 16:22:09 -07001632void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001633{
Brandon Jones6053a522014-07-25 16:22:09 -07001634 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001635}
1636
Brandon Jones6053a522014-07-25 16:22:09 -07001637
Jamie Madill4aa79e12014-09-29 10:46:14 -04001638void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639{
1640 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1641 int levelCount = mipLevels();
1642 for (int level = 1; level < levelCount; level++)
1643 {
1644 redefineImage(level, getBaseLevelInternalFormat(),
1645 std::max(getBaseLevelWidth() >> level, 1),
1646 std::max(getBaseLevelHeight() >> level, 1),
1647 std::max(getBaseLevelDepth() >> level, 1));
1648 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001649}
1650
Jamie Madillac7579c2014-09-17 16:59:33 -04001651unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652{
Jamie Madillc4833262014-09-18 16:18:26 -04001653 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654}
1655
Jamie Madillac7579c2014-09-17 16:59:33 -04001656RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657{
1658 // ensure the underlying texture is created
1659 if (!ensureRenderTarget())
1660 {
1661 return NULL;
1662 }
1663
Jamie Madillac7579c2014-09-17 16:59:33 -04001664 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001665 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001666 updateStorage();
1667 }
1668 else
1669 {
1670 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001671 }
1672
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001673 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674}
1675
1676void TextureD3D_3D::initializeStorage(bool renderTarget)
1677{
1678 // Only initialize the first time this texture is used as a render target or shader resource
1679 if (mTexStorage)
1680 {
1681 return;
1682 }
1683
1684 // do not attempt to create storage for nonexistant data
1685 if (!isLevelComplete(0))
1686 {
1687 return;
1688 }
1689
1690 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1691
1692 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1693 ASSERT(mTexStorage);
1694
1695 // flush image data to the storage
1696 updateStorage();
1697}
1698
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001699TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001700{
1701 GLsizei width = getBaseLevelWidth();
1702 GLsizei height = getBaseLevelHeight();
1703 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001704 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001705
1706 ASSERT(width > 0 && height > 0 && depth > 0);
1707
1708 // use existing storage level count, when previously specified by TexStorage*D
1709 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1710
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001711 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001712}
1713
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001714void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001715{
1716 SafeDelete(mTexStorage);
1717 mTexStorage = newCompleteTexStorage;
1718 mDirtyImages = true;
1719
1720 // We do not support managed 3D storage, as that is D3D9/ES2-only
1721 ASSERT(!mTexStorage->isManaged());
1722}
1723
1724void TextureD3D_3D::updateStorage()
1725{
1726 ASSERT(mTexStorage != NULL);
1727 GLint storageLevels = mTexStorage->getLevelCount();
1728 for (int level = 0; level < storageLevels; level++)
1729 {
1730 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1731 {
1732 updateStorageLevel(level);
1733 }
1734 }
1735}
1736
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737bool TextureD3D_3D::isValidLevel(int level) const
1738{
1739 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1740}
1741
1742bool TextureD3D_3D::isLevelComplete(int level) const
1743{
1744 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1745
1746 if (isImmutable())
1747 {
1748 return true;
1749 }
1750
1751 GLsizei width = getBaseLevelWidth();
1752 GLsizei height = getBaseLevelHeight();
1753 GLsizei depth = getBaseLevelDepth();
1754
1755 if (width <= 0 || height <= 0 || depth <= 0)
1756 {
1757 return false;
1758 }
1759
1760 if (level == 0)
1761 {
1762 return true;
1763 }
1764
1765 ImageD3D *levelImage = mImageArray[level];
1766
1767 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1768 {
1769 return false;
1770 }
1771
1772 if (levelImage->getWidth() != std::max(1, width >> level))
1773 {
1774 return false;
1775 }
1776
1777 if (levelImage->getHeight() != std::max(1, height >> level))
1778 {
1779 return false;
1780 }
1781
1782 if (levelImage->getDepth() != std::max(1, depth >> level))
1783 {
1784 return false;
1785 }
1786
1787 return true;
1788}
1789
1790void TextureD3D_3D::updateStorageLevel(int level)
1791{
1792 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1793 ASSERT(isLevelComplete(level));
1794
1795 if (mImageArray[level]->isDirty())
1796 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001797 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1798 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1799 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001800 }
1801}
1802
1803void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1804{
1805 // If there currently is a corresponding storage texture image, it has these parameters
1806 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1807 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1808 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1809 const GLenum storageFormat = getBaseLevelInternalFormat();
1810
1811 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1812
1813 if (mTexStorage)
1814 {
1815 const int storageLevels = mTexStorage->getLevelCount();
1816
1817 if ((level >= storageLevels && storageLevels != 0) ||
1818 width != storageWidth ||
1819 height != storageHeight ||
1820 depth != storageDepth ||
1821 internalformat != storageFormat) // Discard mismatched storage
1822 {
1823 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1824 {
1825 mImageArray[i]->markDirty();
1826 }
1827
1828 SafeDelete(mTexStorage);
1829 mDirtyImages = true;
1830 }
1831 }
1832}
1833
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001834gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001835{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001836 ASSERT(!index.hasLayer());
1837 GLint level = index.mipIndex;
1838
Brandon Jones78b1acd2014-07-15 15:33:07 -07001839 if (isValidLevel(level))
1840 {
1841 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001842 gl::Error error = image->copyToStorage3D(mTexStorage, level, region.x, region.y, region.z, region.width, region.height, region.depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001843 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001845 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001846 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001847
1848 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001850
1851 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001852}
1853
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001854gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1855{
1856 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1857 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1858}
Brandon Jones142ec422014-07-16 10:31:30 -07001859
Jamie Madillcb83dc12014-09-29 10:46:12 -04001860gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1861{
1862 // The "layer" here does not apply to 3D images. We use one Image per mip.
1863 return gl::ImageIndex::Make3D(mip);
1864}
1865
Brandon Jones142ec422014-07-16 10:31:30 -07001866TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001867 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001868{
1869 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1870 {
1871 mLayerCounts[level] = 0;
1872 mImageArray[level] = NULL;
1873 }
1874}
1875
1876TextureD3D_2DArray::~TextureD3D_2DArray()
1877{
Austin Kinross69822602014-08-12 15:51:37 -07001878 // Delete the Images before the TextureStorage.
1879 // Images might be relying on the TextureStorage for some of their data.
1880 // 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 -07001881 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001882 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001883}
1884
Brandon Jones142ec422014-07-16 10:31:30 -07001885Image *TextureD3D_2DArray::getImage(int level, int layer) const
1886{
1887 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1888 ASSERT(layer < mLayerCounts[level]);
1889 return mImageArray[level][layer];
1890}
1891
Jamie Madillfeda4d22014-09-17 13:03:29 -04001892Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1893{
1894 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1895 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1896 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1897 return mImageArray[index.mipIndex][index.layerIndex];
1898}
1899
Brandon Jones142ec422014-07-16 10:31:30 -07001900GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1901{
1902 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1903 return mLayerCounts[level];
1904}
1905
Brandon Jones142ec422014-07-16 10:31:30 -07001906GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1907{
1908 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1909}
1910
1911GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1912{
1913 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1914}
1915
Brandon Jones142ec422014-07-16 10:31:30 -07001916GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1917{
1918 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1919}
1920
1921bool TextureD3D_2DArray::isDepth(GLint level) const
1922{
Geoff Lang5d601382014-07-22 15:14:06 -04001923 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001924}
1925
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001926gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1927 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1928 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001929{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001930 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1931
Geoff Lang5d601382014-07-22 15:14:06 -04001932 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1933
Brandon Jones142ec422014-07-16 10:31:30 -07001934 redefineImage(level, sizedInternalFormat, width, height, depth);
1935
Geoff Lang5d601382014-07-22 15:14:06 -04001936 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1937 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001938
1939 for (int i = 0; i < depth; i++)
1940 {
1941 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001942 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1943 if (error.isError())
1944 {
1945 return error;
1946 }
Brandon Jones142ec422014-07-16 10:31:30 -07001947 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001948
1949 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001950}
1951
Geoff Langb5348332014-09-02 13:16:34 -04001952gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1953 GLsizei width, GLsizei height, GLsizei depth,
1954 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001955{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001956 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1957
Brandon Jones142ec422014-07-16 10:31:30 -07001958 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1959 redefineImage(level, format, width, height, depth);
1960
Geoff Lang5d601382014-07-22 15:14:06 -04001961 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1962 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001963
1964 for (int i = 0; i < depth; i++)
1965 {
1966 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001967 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1968 if (error.isError())
1969 {
1970 return error;
1971 }
Brandon Jones142ec422014-07-16 10:31:30 -07001972 }
Geoff Langb5348332014-09-02 13:16:34 -04001973
1974 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001975}
1976
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001977gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1978 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1979 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001980{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001981 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1982
Geoff Lang5d601382014-07-22 15:14:06 -04001983 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1984 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001985
1986 for (int i = 0; i < depth; i++)
1987 {
1988 int layer = zoffset + i;
1989 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1990
Jamie Madillfeda4d22014-09-17 13:03:29 -04001991 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04001992 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
1993 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001994 if (error.isError())
1995 {
1996 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07001997 }
1998 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001999
2000 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002001}
2002
Geoff Langb5348332014-09-02 13:16:34 -04002003gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2004 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2005 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002006{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002007 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2008
Geoff Lang5d601382014-07-22 15:14:06 -04002009 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2010 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002011
2012 for (int i = 0; i < depth; i++)
2013 {
2014 int layer = zoffset + i;
2015 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2016
Geoff Langb5348332014-09-02 13:16:34 -04002017 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2018 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002019 {
Geoff Langb5348332014-09-02 13:16:34 -04002020 return error;
2021 }
2022
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002023 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2024 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2025 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002026 if (error.isError())
2027 {
2028 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002029 }
2030 }
Geoff Langb5348332014-09-02 13:16:34 -04002031
2032 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002033}
2034
Brandon Jonescef06ff2014-08-05 13:27:48 -07002035void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2036{
2037 UNIMPLEMENTED();
2038}
2039
Brandon Jones142ec422014-07-16 10:31:30 -07002040void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2041{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002042 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2043
Brandon Jones142ec422014-07-16 10:31:30 -07002044 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2045 // the current level we're copying to is defined (with appropriate format, width & height)
2046 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2047
Jamie Madill82bf0c52014-10-03 11:50:53 -04002048 gl::Rectangle sourceRect(x, y, width, height);
2049
Brandon Jones142ec422014-07-16 10:31:30 -07002050 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2051 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04002052 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jones142ec422014-07-16 10:31:30 -07002053 mDirtyImages = true;
2054 }
2055 else
2056 {
2057 ensureRenderTarget();
2058
2059 if (isValidLevel(level))
2060 {
2061 updateStorageLevel(level);
2062
Jamie Madill856d9d42014-09-18 15:08:49 -04002063 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2064 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002065 }
2066 }
2067}
2068
Brandon Jonescef06ff2014-08-05 13:27:48 -07002069void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002070{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002071 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2072
Brandon Jones142ec422014-07-16 10:31:30 -07002073 deleteImages();
2074
2075 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2076 {
2077 GLsizei levelWidth = std::max(1, width >> level);
2078 GLsizei levelHeight = std::max(1, height >> level);
2079
2080 mLayerCounts[level] = (level < levels ? depth : 0);
2081
2082 if (mLayerCounts[level] > 0)
2083 {
2084 // Create new images for this level
2085 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2086
2087 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2088 {
2089 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2090 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2091 levelHeight, 1, true);
2092 }
2093 }
2094 }
2095
2096 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002097
2098 bool renderTarget = IsRenderTargetUsage(mUsage);
2099 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002100 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002101}
2102
Brandon Jones6053a522014-07-25 16:22:09 -07002103void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002104{
Brandon Jones6053a522014-07-25 16:22:09 -07002105 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002106}
2107
Brandon Jones6053a522014-07-25 16:22:09 -07002108void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002109{
Brandon Jones6053a522014-07-25 16:22:09 -07002110 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002111}
2112
Brandon Jones6053a522014-07-25 16:22:09 -07002113
Jamie Madill4aa79e12014-09-29 10:46:14 -04002114void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002115{
2116 int baseWidth = getBaseLevelWidth();
2117 int baseHeight = getBaseLevelHeight();
2118 int baseDepth = getBaseLevelDepth();
2119 GLenum baseFormat = getBaseLevelInternalFormat();
2120
2121 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2122 int levelCount = mipLevels();
2123 for (int level = 1; level < levelCount; level++)
2124 {
2125 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2126 }
Brandon Jones142ec422014-07-16 10:31:30 -07002127}
2128
Jamie Madillac7579c2014-09-17 16:59:33 -04002129unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002130{
Jamie Madillc4833262014-09-18 16:18:26 -04002131 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002132}
2133
Jamie Madillac7579c2014-09-17 16:59:33 -04002134RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002135{
2136 // ensure the underlying texture is created
2137 if (!ensureRenderTarget())
2138 {
2139 return NULL;
2140 }
2141
Jamie Madillac7579c2014-09-17 16:59:33 -04002142 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002143 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002144}
2145
2146void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2147{
2148 // Only initialize the first time this texture is used as a render target or shader resource
2149 if (mTexStorage)
2150 {
2151 return;
2152 }
2153
2154 // do not attempt to create storage for nonexistant data
2155 if (!isLevelComplete(0))
2156 {
2157 return;
2158 }
2159
2160 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2161
2162 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2163 ASSERT(mTexStorage);
2164
2165 // flush image data to the storage
2166 updateStorage();
2167}
2168
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002169TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002170{
2171 GLsizei width = getBaseLevelWidth();
2172 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002173 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002174 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002175
2176 ASSERT(width > 0 && height > 0 && depth > 0);
2177
2178 // use existing storage level count, when previously specified by TexStorage*D
2179 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2180
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002181 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002182}
2183
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002184void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002185{
2186 SafeDelete(mTexStorage);
2187 mTexStorage = newCompleteTexStorage;
2188 mDirtyImages = true;
2189
2190 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2191 ASSERT(!mTexStorage->isManaged());
2192}
2193
2194void TextureD3D_2DArray::updateStorage()
2195{
2196 ASSERT(mTexStorage != NULL);
2197 GLint storageLevels = mTexStorage->getLevelCount();
2198 for (int level = 0; level < storageLevels; level++)
2199 {
2200 if (isLevelComplete(level))
2201 {
2202 updateStorageLevel(level);
2203 }
2204 }
2205}
2206
Brandon Jones142ec422014-07-16 10:31:30 -07002207bool TextureD3D_2DArray::isValidLevel(int level) const
2208{
2209 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2210}
2211
2212bool TextureD3D_2DArray::isLevelComplete(int level) const
2213{
2214 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2215
2216 if (isImmutable())
2217 {
2218 return true;
2219 }
2220
2221 GLsizei width = getBaseLevelWidth();
2222 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002223 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002224
2225 if (width <= 0 || height <= 0 || layers <= 0)
2226 {
2227 return false;
2228 }
2229
2230 if (level == 0)
2231 {
2232 return true;
2233 }
2234
2235 if (getInternalFormat(level) != getInternalFormat(0))
2236 {
2237 return false;
2238 }
2239
2240 if (getWidth(level) != std::max(1, width >> level))
2241 {
2242 return false;
2243 }
2244
2245 if (getHeight(level) != std::max(1, height >> level))
2246 {
2247 return false;
2248 }
2249
Jamie Madill3269bcb2014-09-30 16:33:52 -04002250 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002251 {
2252 return false;
2253 }
2254
2255 return true;
2256}
2257
2258void TextureD3D_2DArray::updateStorageLevel(int level)
2259{
2260 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2261 ASSERT(isLevelComplete(level));
2262
2263 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2264 {
2265 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2266 if (mImageArray[level][layer]->isDirty())
2267 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002268 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2269 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2270 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002271 }
2272 }
2273}
2274
2275void TextureD3D_2DArray::deleteImages()
2276{
2277 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2278 {
2279 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2280 {
2281 delete mImageArray[level][layer];
2282 }
2283 delete[] mImageArray[level];
2284 mImageArray[level] = NULL;
2285 mLayerCounts[level] = 0;
2286 }
2287}
2288
2289void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2290{
2291 // If there currently is a corresponding storage texture image, it has these parameters
2292 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2293 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002294 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002295 const GLenum storageFormat = getBaseLevelInternalFormat();
2296
2297 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2298 {
2299 delete mImageArray[level][layer];
2300 }
2301 delete[] mImageArray[level];
2302 mImageArray[level] = NULL;
2303 mLayerCounts[level] = depth;
2304
2305 if (depth > 0)
2306 {
2307 mImageArray[level] = new ImageD3D*[depth]();
2308
2309 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2310 {
2311 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2312 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2313 }
2314 }
2315
2316 if (mTexStorage)
2317 {
2318 const int storageLevels = mTexStorage->getLevelCount();
2319
2320 if ((level >= storageLevels && storageLevels != 0) ||
2321 width != storageWidth ||
2322 height != storageHeight ||
2323 depth != storageDepth ||
2324 internalformat != storageFormat) // Discard mismatched storage
2325 {
2326 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2327 {
2328 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2329 {
2330 mImageArray[level][layer]->markDirty();
2331 }
2332 }
2333
2334 delete mTexStorage;
2335 mTexStorage = NULL;
2336 mDirtyImages = true;
2337 }
2338 }
2339}
2340
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002341gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002342{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002343 ASSERT(index.hasLayer());
2344 GLint level = index.mipIndex;
2345 GLint layerTarget = index.layerIndex;
2346
Jamie Madill3269bcb2014-09-30 16:33:52 -04002347 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002348 {
2349 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002350 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, region.x, region.y, layerTarget, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002351 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002352 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002353 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002354 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002355
2356 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002357 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002358
2359 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002360}
2361
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002362gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2363{
2364 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2365}
2366
Jamie Madillcb83dc12014-09-29 10:46:12 -04002367gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2368{
2369 return gl::ImageIndex::Make2DArray(mip, layer);
2370}
2371
Brandon Jones78b1acd2014-07-15 15:33:07 -07002372}