blob: 5e29e4b45be7c4473df38c75ff250125a7f62698 [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),
38 mImmutable(false)
39{
40}
41
42TextureD3D::~TextureD3D()
43{
44}
45
Brandon Jones6053a522014-07-25 16:22:09 -070046TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
47{
48 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
49 return static_cast<TextureD3D*>(texture);
50}
51
52TextureStorageInterface *TextureD3D::getNativeTexture()
53{
54 // ensure the underlying texture is created
55 initializeStorage(false);
56
57 TextureStorageInterface *storage = getBaseLevelStorage();
58 if (storage)
59 {
60 updateStorage();
61 }
62
63 return storage;
64}
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
Brandon Jones78b1acd2014-07-15 15:33:07 -070093void 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 {
98 return;
99 }
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 {
118 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 mDirtyImages = true;
120 }
121}
122
123bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700124 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700125{
126 const void *pixelData = pixels;
127
128 // CPU readback & copy where direct GPU copy is not supported
129 if (unpack.pixelBuffer.id() != 0)
130 {
131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
132 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
134 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
135 const void *bufferData = pixelBuffer->getImplementation()->getData();
136 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
137 }
138
139 if (pixelData != NULL)
140 {
141 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
142 mDirtyImages = true;
143 }
144
145 return true;
146}
147
Brandon Jones78b1acd2014-07-15 15:33:07 -0700148void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700149{
150 if (pixels != NULL)
151 {
152 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
153 mDirtyImages = true;
154 }
155}
156
157bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700158 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700159{
160 if (pixels != NULL)
161 {
162 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
163 mDirtyImages = true;
164 }
165
166 return true;
167}
168
169bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
170{
171 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
172}
173
174bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700175 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700176{
177 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
178 {
179 return true;
180 }
181
182 // In order to perform the fast copy through the shader, we must have the right format, and be able
183 // to create a render target.
184 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
185
186 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
187
188 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
189}
190
191GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
192{
193 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
194 {
195 // Maximum number of levels
196 return gl::log2(std::max(std::max(width, height), depth)) + 1;
197 }
198 else
199 {
200 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
201 return 1;
202 }
203}
204
205int TextureD3D::mipLevels() const
206{
207 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
208}
209
210
Brandon Jones78b1acd2014-07-15 15:33:07 -0700211TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700212 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700213 mTexStorage(NULL)
214{
215 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
216 {
217 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
218 }
219}
220
221TextureD3D_2D::~TextureD3D_2D()
222{
Austin Kinross69822602014-08-12 15:51:37 -0700223 // Delete the Images before the TextureStorage.
224 // Images might be relying on the TextureStorage for some of their data.
225 // 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 -0700226 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
227 {
228 delete mImageArray[i];
229 }
Austin Kinross69822602014-08-12 15:51:37 -0700230
231 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700232}
233
Brandon Jonescef06ff2014-08-05 13:27:48 -0700234Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700235{
236 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700237 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238 return mImageArray[level];
239}
240
Brandon Jonescef06ff2014-08-05 13:27:48 -0700241GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700242{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700243 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
244 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700245}
246
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700247GLsizei TextureD3D_2D::getWidth(GLint level) const
248{
249 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
250 return mImageArray[level]->getWidth();
251 else
252 return 0;
253}
254
255GLsizei TextureD3D_2D::getHeight(GLint level) const
256{
257 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
258 return mImageArray[level]->getHeight();
259 else
260 return 0;
261}
262
263GLenum TextureD3D_2D::getInternalFormat(GLint level) const
264{
265 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
266 return mImageArray[level]->getInternalFormat();
267 else
268 return GL_NONE;
269}
270
271GLenum TextureD3D_2D::getActualFormat(GLint level) const
272{
273 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
274 return mImageArray[level]->getActualFormat();
275 else
276 return GL_NONE;
277}
278
279bool TextureD3D_2D::isDepth(GLint level) const
280{
Geoff Lang5d601382014-07-22 15:14:06 -0400281 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700282}
283
Brandon Jonescef06ff2014-08-05 13:27:48 -0700284void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700285{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700286 ASSERT(target == GL_TEXTURE_2D && depth == 1);
287
Geoff Lang5d601382014-07-22 15:14:06 -0400288 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
289
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700290 bool fastUnpacked = false;
291
Brandon Jonescef06ff2014-08-05 13:27:48 -0700292 redefineImage(level, sizedInternalFormat, width, height);
293
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294 // Attempt a fast gpu copy of the pixel data to the surface
295 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
296 {
297 // Will try to create RT storage if it does not exist
Brandon Jonescef06ff2014-08-05 13:27:48 -0700298 RenderTarget *destRenderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700299 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
300
301 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
302 {
303 // Ensure we don't overwrite our newly initialized data
304 mImageArray[level]->markClean();
305
306 fastUnpacked = true;
307 }
308 }
309
310 if (!fastUnpacked)
311 {
312 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
313 }
314}
315
Brandon Jonescef06ff2014-08-05 13:27:48 -0700316void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700317{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700318 ASSERT(target == GL_TEXTURE_2D && depth == 1);
319
320 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
321 redefineImage(level, format, width, height);
322
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700323 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
324}
325
Brandon Jonescef06ff2014-08-05 13:27:48 -0700326void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700327{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700328 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
329
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700330 bool fastUnpacked = false;
331
332 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
333 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700334 RenderTarget *renderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700335 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
336
337 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
338 {
339 // Ensure we don't overwrite our newly initialized data
340 mImageArray[level]->markClean();
341
342 fastUnpacked = true;
343 }
344 }
345
346 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
347 {
348 commitRect(level, xoffset, yoffset, width, height);
349 }
350}
351
Brandon Jonescef06ff2014-08-05 13:27:48 -0700352void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700353{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700354 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
355
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700356 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
357 {
358 commitRect(level, xoffset, yoffset, width, height);
359 }
360}
361
Brandon Jonescef06ff2014-08-05 13:27:48 -0700362void 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 -0700363{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700364 ASSERT(target == GL_TEXTURE_2D);
365
366 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
367 redefineImage(level, sizedInternalFormat, width, height);
368
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700369 if (!mImageArray[level]->isRenderableFormat())
370 {
371 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
372 mDirtyImages = true;
373 }
374 else
375 {
376 ensureRenderTarget();
377 mImageArray[level]->markClean();
378
379 if (width != 0 && height != 0 && isValidLevel(level))
380 {
381 gl::Rectangle sourceRect;
382 sourceRect.x = x;
383 sourceRect.width = width;
384 sourceRect.y = y;
385 sourceRect.height = height;
386
387 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
388 }
389 }
390}
391
392void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
393{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700394 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
395
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700396 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
397 // the current level we're copying to is defined (with appropriate format, width & height)
398 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
399
400 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
401 {
402 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
403 mDirtyImages = true;
404 }
405 else
406 {
407 ensureRenderTarget();
408
409 if (isValidLevel(level))
410 {
411 updateStorageLevel(level);
412
413 gl::Rectangle sourceRect;
414 sourceRect.x = x;
415 sourceRect.width = width;
416 sourceRect.y = y;
417 sourceRect.height = height;
418
419 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400420 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421 xoffset, yoffset, mTexStorage, level);
422 }
423 }
424}
425
Brandon Jonescef06ff2014-08-05 13:27:48 -0700426void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700427{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700428 ASSERT(target == GL_TEXTURE_2D && depth == 1);
429
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700430 for (int level = 0; level < levels; level++)
431 {
432 GLsizei levelWidth = std::max(1, width >> level);
433 GLsizei levelHeight = std::max(1, height >> level);
434 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
435 }
436
437 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
438 {
439 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
440 }
441
442 mImmutable = true;
443
Brandon Jones78b1acd2014-07-15 15:33:07 -0700444 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700445}
446
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700447void TextureD3D_2D::bindTexImage(egl::Surface *surface)
448{
449 GLenum internalformat = surface->getFormat();
450
451 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
452
453 if (mTexStorage)
454 {
455 SafeDelete(mTexStorage);
456 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700457 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700458
459 mDirtyImages = true;
460}
461
462void TextureD3D_2D::releaseTexImage()
463{
464 if (mTexStorage)
465 {
466 SafeDelete(mTexStorage);
467 }
468
469 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
470 {
471 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
472 }
473}
474
475void TextureD3D_2D::generateMipmaps()
476{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700477 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700478 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700479 for (int level = 1; level < levelCount; level++)
480 {
481 redefineImage(level, getBaseLevelInternalFormat(),
482 std::max(getBaseLevelWidth() >> level, 1),
483 std::max(getBaseLevelHeight() >> level, 1));
484 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700485
486 if (mTexStorage && mTexStorage->isRenderTarget())
487 {
488 for (int level = 1; level < levelCount; level++)
489 {
490 mTexStorage->generateMipmap(level);
491
492 mImageArray[level]->markClean();
493 }
494 }
495 else
496 {
497 for (int level = 1; level < levelCount; level++)
498 {
499 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
500 }
501 }
502}
503
Brandon Jonescef06ff2014-08-05 13:27:48 -0700504unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700506 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700507 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
508}
509
Brandon Jonescef06ff2014-08-05 13:27:48 -0700510RenderTarget *TextureD3D_2D::getRenderTarget(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700511{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700512 ASSERT(layer == 0);
513
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700514 // ensure the underlying texture is created
515 if (!ensureRenderTarget())
516 {
517 return NULL;
518 }
519
520 updateStorageLevel(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700521 return mTexStorage->getRenderTarget(level);
522}
523
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700524bool TextureD3D_2D::isValidLevel(int level) const
525{
526 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
527}
528
529bool TextureD3D_2D::isLevelComplete(int level) const
530{
531 if (isImmutable())
532 {
533 return true;
534 }
535
Brandon Jones78b1acd2014-07-15 15:33:07 -0700536 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700537
538 GLsizei width = baseImage->getWidth();
539 GLsizei height = baseImage->getHeight();
540
541 if (width <= 0 || height <= 0)
542 {
543 return false;
544 }
545
546 // The base image level is complete if the width and height are positive
547 if (level == 0)
548 {
549 return true;
550 }
551
552 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700553 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700554
555 if (image->getInternalFormat() != baseImage->getInternalFormat())
556 {
557 return false;
558 }
559
560 if (image->getWidth() != std::max(1, width >> level))
561 {
562 return false;
563 }
564
565 if (image->getHeight() != std::max(1, height >> level))
566 {
567 return false;
568 }
569
570 return true;
571}
572
573// Constructs a native texture resource from the texture images
574void TextureD3D_2D::initializeStorage(bool renderTarget)
575{
576 // Only initialize the first time this texture is used as a render target or shader resource
577 if (mTexStorage)
578 {
579 return;
580 }
581
582 // do not attempt to create storage for nonexistant data
583 if (!isLevelComplete(0))
584 {
585 return;
586 }
587
588 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
589
590 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
591 ASSERT(mTexStorage);
592
593 // flush image data to the storage
594 updateStorage();
595}
596
Brandon Jones78b1acd2014-07-15 15:33:07 -0700597TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700598{
599 GLsizei width = getBaseLevelWidth();
600 GLsizei height = getBaseLevelHeight();
601
602 ASSERT(width > 0 && height > 0);
603
604 // use existing storage level count, when previously specified by TexStorage*D
605 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
606
Brandon Jones78b1acd2014-07-15 15:33:07 -0700607 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608}
609
610void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
611{
612 SafeDelete(mTexStorage);
613 mTexStorage = newCompleteTexStorage;
614
615 if (mTexStorage && mTexStorage->isManaged())
616 {
617 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
618 {
619 mImageArray[level]->setManagedSurface(mTexStorage, level);
620 }
621 }
622
623 mDirtyImages = true;
624}
625
626void TextureD3D_2D::updateStorage()
627{
628 ASSERT(mTexStorage != NULL);
629 GLint storageLevels = mTexStorage->getLevelCount();
630 for (int level = 0; level < storageLevels; level++)
631 {
632 if (mImageArray[level]->isDirty() && isLevelComplete(level))
633 {
634 updateStorageLevel(level);
635 }
636 }
637}
638
639bool TextureD3D_2D::ensureRenderTarget()
640{
641 initializeStorage(true);
642
643 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
644 {
645 ASSERT(mTexStorage);
646 if (!mTexStorage->isRenderTarget())
647 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700648 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700649
650 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
651 {
652 delete newRenderTargetStorage;
653 return gl::error(GL_OUT_OF_MEMORY, false);
654 }
655
656 setCompleteTexStorage(newRenderTargetStorage);
657 }
658 }
659
660 return (mTexStorage && mTexStorage->isRenderTarget());
661}
662
663TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
664{
665 return mTexStorage;
666}
667
668const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
669{
670 return mImageArray[0];
671}
672
673void TextureD3D_2D::updateStorageLevel(int level)
674{
675 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
676 ASSERT(isLevelComplete(level));
677
678 if (mImageArray[level]->isDirty())
679 {
680 commitRect(level, 0, 0, getWidth(level), getHeight(level));
681 }
682}
683
684void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
685{
686 // If there currently is a corresponding storage texture image, it has these parameters
687 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
688 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
689 const GLenum storageFormat = getBaseLevelInternalFormat();
690
691 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
692
693 if (mTexStorage)
694 {
695 const int storageLevels = mTexStorage->getLevelCount();
696
697 if ((level >= storageLevels && storageLevels != 0) ||
698 width != storageWidth ||
699 height != storageHeight ||
700 internalformat != storageFormat) // Discard mismatched storage
701 {
702 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
703 {
704 mImageArray[i]->markDirty();
705 }
706
707 SafeDelete(mTexStorage);
708 mDirtyImages = true;
709 }
710 }
711}
712
713void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
714{
715 if (isValidLevel(level))
716 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700717 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700718 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
719 {
720 image->markClean();
721 }
722 }
723}
724
Brandon Jones0511e802014-07-14 16:27:26 -0700725
Brandon Jones78b1acd2014-07-15 15:33:07 -0700726TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700727 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700728 mTexStorage(NULL)
729{
730 for (int i = 0; i < 6; i++)
731 {
732 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
733 {
734 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
735 }
736 }
737}
738
739TextureD3D_Cube::~TextureD3D_Cube()
740{
Austin Kinross69822602014-08-12 15:51:37 -0700741 // Delete the Images before the TextureStorage.
742 // Images might be relying on the TextureStorage for some of their data.
743 // 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 -0700744 for (int i = 0; i < 6; i++)
745 {
746 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
747 {
748 SafeDelete(mImageArray[i][j]);
749 }
750 }
Austin Kinross69822602014-08-12 15:51:37 -0700751
752 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700753}
754
Brandon Jonescef06ff2014-08-05 13:27:48 -0700755Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700756{
757 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700758 ASSERT(layer < 6);
759 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700760}
761
Brandon Jonescef06ff2014-08-05 13:27:48 -0700762GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700763{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700764 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
765 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700766}
767
Brandon Jonescef06ff2014-08-05 13:27:48 -0700768GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700769{
770 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700771 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700772 else
773 return GL_NONE;
774}
775
Brandon Jonescef06ff2014-08-05 13:27:48 -0700776bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700777{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700778 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700779}
780
Brandon Jonescef06ff2014-08-05 13:27:48 -0700781void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700782{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700783 ASSERT(depth == 1);
784
785 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400786 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700787
788 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
789
790 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
791}
792
Brandon Jonescef06ff2014-08-05 13:27:48 -0700793void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700794{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700795 ASSERT(depth == 1);
796
Brandon Jones0511e802014-07-14 16:27:26 -0700797 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700798 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
799
Brandon Jones0511e802014-07-14 16:27:26 -0700800 redefineImage(faceIndex, level, format, width, height);
801
802 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
803}
804
Brandon Jonescef06ff2014-08-05 13:27:48 -0700805void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700806{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700807 ASSERT(depth == 1 && zoffset == 0);
808
809 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
810
Brandon Jones0511e802014-07-14 16:27:26 -0700811 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
812 {
813 commitRect(faceIndex, level, xoffset, yoffset, width, height);
814 }
815}
816
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700818{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700819 ASSERT(depth == 1 && zoffset == 0);
820
821 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
822
Brandon Jones0511e802014-07-14 16:27:26 -0700823 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
824 {
825 commitRect(faceIndex, level, xoffset, yoffset, width, height);
826 }
827}
828
829void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
830{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700831 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400832 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
833
Brandon Jones0511e802014-07-14 16:27:26 -0700834 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
835
836 if (!mImageArray[faceIndex][level]->isRenderableFormat())
837 {
838 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
839 mDirtyImages = true;
840 }
841 else
842 {
843 ensureRenderTarget();
844 mImageArray[faceIndex][level]->markClean();
845
846 ASSERT(width == height);
847
848 if (width > 0 && isValidFaceLevel(faceIndex, level))
849 {
850 gl::Rectangle sourceRect;
851 sourceRect.x = x;
852 sourceRect.width = width;
853 sourceRect.y = y;
854 sourceRect.height = height;
855
856 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
857 }
858 }
859}
860
861void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
862{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700863 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700864
865 // We can only make our texture storage to a render target if the level we're copying *to* is complete
866 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
867 // rely on the "getBaseLevel*" methods reliably otherwise.
868 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
869
870 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
871 {
872 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
873 mDirtyImages = true;
874 }
875 else
876 {
877 ensureRenderTarget();
878
879 if (isValidFaceLevel(faceIndex, level))
880 {
881 updateStorageFaceLevel(faceIndex, level);
882
883 gl::Rectangle sourceRect;
884 sourceRect.x = x;
885 sourceRect.width = width;
886 sourceRect.y = y;
887 sourceRect.height = height;
888
Geoff Lang5d601382014-07-22 15:14:06 -0400889 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700890 xoffset, yoffset, mTexStorage, target, level);
891 }
892 }
893}
894
Brandon Jonescef06ff2014-08-05 13:27:48 -0700895void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700896{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700897 ASSERT(width == height);
898 ASSERT(depth == 1);
899
Brandon Jones0511e802014-07-14 16:27:26 -0700900 for (int level = 0; level < levels; level++)
901 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700902 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700903 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
904 {
905 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
906 }
907 }
908
909 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
910 {
911 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
912 {
913 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
914 }
915 }
916
917 mImmutable = true;
918
Brandon Jonescef06ff2014-08-05 13:27:48 -0700919 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700920}
921
Brandon Jones0511e802014-07-14 16:27:26 -0700922// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
923bool TextureD3D_Cube::isCubeComplete() const
924{
925 int baseWidth = getBaseLevelWidth();
926 int baseHeight = getBaseLevelHeight();
927 GLenum baseFormat = getBaseLevelInternalFormat();
928
929 if (baseWidth <= 0 || baseWidth != baseHeight)
930 {
931 return false;
932 }
933
934 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
935 {
936 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
937
938 if (faceBaseImage.getWidth() != baseWidth ||
939 faceBaseImage.getHeight() != baseHeight ||
940 faceBaseImage.getInternalFormat() != baseFormat )
941 {
942 return false;
943 }
944 }
945
946 return true;
947}
948
Brandon Jones6053a522014-07-25 16:22:09 -0700949void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
950{
951 UNREACHABLE();
952}
953
954void TextureD3D_Cube::releaseTexImage()
955{
956 UNREACHABLE();
957}
958
959
Brandon Jones0511e802014-07-14 16:27:26 -0700960void TextureD3D_Cube::generateMipmaps()
961{
962 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
963 int levelCount = mipLevels();
964 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
965 {
966 for (int level = 1; level < levelCount; level++)
967 {
968 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
969 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
970 }
971 }
972
973 if (mTexStorage && mTexStorage->isRenderTarget())
974 {
975 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
976 {
977 for (int level = 1; level < levelCount; level++)
978 {
979 mTexStorage->generateMipmap(faceIndex, level);
980
981 mImageArray[faceIndex][level]->markClean();
982 }
983 }
984 }
985 else
986 {
987 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
988 {
989 for (int level = 1; level < levelCount; level++)
990 {
991 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
992 }
993 }
994 }
995}
996
Brandon Jonescef06ff2014-08-05 13:27:48 -0700997unsigned int TextureD3D_Cube::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -0700998{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700999 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001000 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1001}
1002
Brandon Jonescef06ff2014-08-05 13:27:48 -07001003RenderTarget *TextureD3D_Cube::getRenderTarget(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001004{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001005 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001006 ASSERT(gl::IsCubemapTextureTarget(target));
1007
1008 // ensure the underlying texture is created
1009 if (!ensureRenderTarget())
1010 {
1011 return NULL;
1012 }
1013
Brandon Jonescef06ff2014-08-05 13:27:48 -07001014 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001015 return mTexStorage->getRenderTarget(target, level);
1016}
1017
Brandon Jones0511e802014-07-14 16:27:26 -07001018void TextureD3D_Cube::initializeStorage(bool renderTarget)
1019{
1020 // Only initialize the first time this texture is used as a render target or shader resource
1021 if (mTexStorage)
1022 {
1023 return;
1024 }
1025
1026 // do not attempt to create storage for nonexistant data
1027 if (!isFaceLevelComplete(0, 0))
1028 {
1029 return;
1030 }
1031
1032 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1033
1034 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1035 ASSERT(mTexStorage);
1036
1037 // flush image data to the storage
1038 updateStorage();
1039}
1040
1041TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1042{
1043 GLsizei size = getBaseLevelWidth();
1044
1045 ASSERT(size > 0);
1046
1047 // use existing storage level count, when previously specified by TexStorage*D
1048 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1049
1050 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1051}
1052
1053void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1054{
1055 SafeDelete(mTexStorage);
1056 mTexStorage = newCompleteTexStorage;
1057
1058 if (mTexStorage && mTexStorage->isManaged())
1059 {
1060 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1061 {
1062 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1063 {
1064 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1065 }
1066 }
1067 }
1068
1069 mDirtyImages = true;
1070}
1071
1072void TextureD3D_Cube::updateStorage()
1073{
1074 ASSERT(mTexStorage != NULL);
1075 GLint storageLevels = mTexStorage->getLevelCount();
1076 for (int face = 0; face < 6; face++)
1077 {
1078 for (int level = 0; level < storageLevels; level++)
1079 {
1080 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1081 {
1082 updateStorageFaceLevel(face, level);
1083 }
1084 }
1085 }
1086}
1087
1088bool TextureD3D_Cube::ensureRenderTarget()
1089{
1090 initializeStorage(true);
1091
1092 if (getBaseLevelWidth() > 0)
1093 {
1094 ASSERT(mTexStorage);
1095 if (!mTexStorage->isRenderTarget())
1096 {
1097 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1098
1099 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1100 {
1101 delete newRenderTargetStorage;
1102 return gl::error(GL_OUT_OF_MEMORY, false);
1103 }
1104
1105 setCompleteTexStorage(newRenderTargetStorage);
1106 }
1107 }
1108
1109 return (mTexStorage && mTexStorage->isRenderTarget());
1110}
1111
1112TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1113{
1114 return mTexStorage;
1115}
1116
1117const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1118{
1119 // Note: if we are not cube-complete, there is no single base level image that can describe all
1120 // cube faces, so this method is only well-defined for a cube-complete base level.
1121 return mImageArray[0][0];
1122}
1123
Brandon Jones0511e802014-07-14 16:27:26 -07001124bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1125{
1126 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1127}
1128
Brandon Jones0511e802014-07-14 16:27:26 -07001129bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1130{
1131 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1132
1133 if (isImmutable())
1134 {
1135 return true;
1136 }
1137
1138 int baseSize = getBaseLevelWidth();
1139
1140 if (baseSize <= 0)
1141 {
1142 return false;
1143 }
1144
1145 // "isCubeComplete" checks for base level completeness and we must call that
1146 // to determine if any face at level 0 is complete. We omit that check here
1147 // to avoid re-checking cube-completeness for every face at level 0.
1148 if (level == 0)
1149 {
1150 return true;
1151 }
1152
1153 // Check that non-zero levels are consistent with the base level.
1154 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1155
1156 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1157 {
1158 return false;
1159 }
1160
1161 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1162 {
1163 return false;
1164 }
1165
1166 return true;
1167}
1168
1169void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1170{
1171 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1172 ImageD3D *image = mImageArray[faceIndex][level];
1173
1174 if (image->isDirty())
1175 {
1176 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1177 }
1178}
1179
1180void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1181{
1182 // If there currently is a corresponding storage texture image, it has these parameters
1183 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1184 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1185 const GLenum storageFormat = getBaseLevelInternalFormat();
1186
1187 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1188
1189 if (mTexStorage)
1190 {
1191 const int storageLevels = mTexStorage->getLevelCount();
1192
1193 if ((level >= storageLevels && storageLevels != 0) ||
1194 width != storageWidth ||
1195 height != storageHeight ||
1196 internalformat != storageFormat) // Discard mismatched storage
1197 {
1198 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1199 {
1200 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1201 {
1202 mImageArray[faceIndex][level]->markDirty();
1203 }
1204 }
1205
1206 SafeDelete(mTexStorage);
1207
1208 mDirtyImages = true;
1209 }
1210 }
1211}
1212
1213void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1214{
1215 if (isValidFaceLevel(faceIndex, level))
1216 {
1217 ImageD3D *image = mImageArray[faceIndex][level];
1218 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1219 image->markClean();
1220 }
1221}
1222
Brandon Jones78b1acd2014-07-15 15:33:07 -07001223
1224TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001225 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001226 mTexStorage(NULL)
1227{
1228 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1229 {
1230 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1231 }
1232}
1233
1234TextureD3D_3D::~TextureD3D_3D()
1235{
Austin Kinross69822602014-08-12 15:51:37 -07001236 // Delete the Images before the TextureStorage.
1237 // Images might be relying on the TextureStorage for some of their data.
1238 // 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 -07001239 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1240 {
1241 delete mImageArray[i];
1242 }
Austin Kinross69822602014-08-12 15:51:37 -07001243
1244 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001245}
1246
Brandon Jonescef06ff2014-08-05 13:27:48 -07001247Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001248{
1249 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001250 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001251 return mImageArray[level];
1252}
1253
Brandon Jonescef06ff2014-08-05 13:27:48 -07001254GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001255{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001256 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1257 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001258}
1259
Brandon Jones78b1acd2014-07-15 15:33:07 -07001260GLsizei TextureD3D_3D::getWidth(GLint level) const
1261{
1262 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1263 return mImageArray[level]->getWidth();
1264 else
1265 return 0;
1266}
1267
1268GLsizei TextureD3D_3D::getHeight(GLint level) const
1269{
1270 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1271 return mImageArray[level]->getHeight();
1272 else
1273 return 0;
1274}
1275
1276GLsizei TextureD3D_3D::getDepth(GLint level) const
1277{
1278 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1279 return mImageArray[level]->getDepth();
1280 else
1281 return 0;
1282}
1283
1284GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1285{
1286 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1287 return mImageArray[level]->getInternalFormat();
1288 else
1289 return GL_NONE;
1290}
1291
1292bool TextureD3D_3D::isDepth(GLint level) const
1293{
Geoff Lang5d601382014-07-22 15:14:06 -04001294 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001295}
1296
Brandon Jonescef06ff2014-08-05 13:27:48 -07001297void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001298{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001299 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001300 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1301
Brandon Jones78b1acd2014-07-15 15:33:07 -07001302 redefineImage(level, sizedInternalFormat, width, height, depth);
1303
1304 bool fastUnpacked = false;
1305
1306 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1307 if (isFastUnpackable(unpack, sizedInternalFormat))
1308 {
1309 // Will try to create RT storage if it does not exist
1310 RenderTarget *destRenderTarget = getRenderTarget(level);
1311 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1312
1313 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1314 {
1315 // Ensure we don't overwrite our newly initialized data
1316 mImageArray[level]->markClean();
1317
1318 fastUnpacked = true;
1319 }
1320 }
1321
1322 if (!fastUnpacked)
1323 {
1324 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1325 }
1326}
1327
Brandon Jonescef06ff2014-08-05 13:27:48 -07001328void TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001329{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001330 ASSERT(target == GL_TEXTURE_3D);
1331
Brandon Jones78b1acd2014-07-15 15:33:07 -07001332 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1333 redefineImage(level, format, width, height, depth);
1334
1335 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1336}
1337
Brandon Jonescef06ff2014-08-05 13:27:48 -07001338void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001339{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001340 ASSERT(target == GL_TEXTURE_3D);
1341
Brandon Jones78b1acd2014-07-15 15:33:07 -07001342 bool fastUnpacked = false;
1343
1344 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1345 if (isFastUnpackable(unpack, getInternalFormat(level)))
1346 {
1347 RenderTarget *destRenderTarget = getRenderTarget(level);
1348 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1349
1350 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1351 {
1352 // Ensure we don't overwrite our newly initialized data
1353 mImageArray[level]->markClean();
1354
1355 fastUnpacked = true;
1356 }
1357 }
1358
1359 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1360 {
1361 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1362 }
1363}
1364
Brandon Jonescef06ff2014-08-05 13:27:48 -07001365void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001366{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001367 ASSERT(target == GL_TEXTURE_3D);
1368
Brandon Jones78b1acd2014-07-15 15:33:07 -07001369 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1370 {
1371 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1372 }
1373}
1374
Brandon Jonescef06ff2014-08-05 13:27:48 -07001375void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1376{
1377 UNIMPLEMENTED();
1378}
1379
Brandon Jones78b1acd2014-07-15 15:33:07 -07001380void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1381{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001382 ASSERT(target == GL_TEXTURE_3D);
1383
Brandon Jones78b1acd2014-07-15 15:33:07 -07001384 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1385 // the current level we're copying to is defined (with appropriate format, width & height)
1386 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1387
1388 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1389 {
1390 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1391 mDirtyImages = true;
1392 }
1393 else
1394 {
1395 ensureRenderTarget();
1396
1397 if (isValidLevel(level))
1398 {
1399 updateStorageLevel(level);
1400
1401 gl::Rectangle sourceRect;
1402 sourceRect.x = x;
1403 sourceRect.width = width;
1404 sourceRect.y = y;
1405 sourceRect.height = height;
1406
1407 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001408 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001409 xoffset, yoffset, zoffset, mTexStorage, level);
1410 }
1411 }
1412}
1413
Brandon Jonescef06ff2014-08-05 13:27:48 -07001414void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001415{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001416 ASSERT(target == GL_TEXTURE_3D);
1417
Brandon Jones78b1acd2014-07-15 15:33:07 -07001418 for (int level = 0; level < levels; level++)
1419 {
1420 GLsizei levelWidth = std::max(1, width >> level);
1421 GLsizei levelHeight = std::max(1, height >> level);
1422 GLsizei levelDepth = std::max(1, depth >> level);
1423 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1424 }
1425
1426 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1427 {
1428 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1429 }
1430
1431 mImmutable = true;
1432
1433 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1434}
1435
Brandon Jones6053a522014-07-25 16:22:09 -07001436void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001437{
Brandon Jones6053a522014-07-25 16:22:09 -07001438 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001439}
1440
Brandon Jones6053a522014-07-25 16:22:09 -07001441void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001442{
Brandon Jones6053a522014-07-25 16:22:09 -07001443 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001444}
1445
Brandon Jones6053a522014-07-25 16:22:09 -07001446
Brandon Jones78b1acd2014-07-15 15:33:07 -07001447void TextureD3D_3D::generateMipmaps()
1448{
1449 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1450 int levelCount = mipLevels();
1451 for (int level = 1; level < levelCount; level++)
1452 {
1453 redefineImage(level, getBaseLevelInternalFormat(),
1454 std::max(getBaseLevelWidth() >> level, 1),
1455 std::max(getBaseLevelHeight() >> level, 1),
1456 std::max(getBaseLevelDepth() >> level, 1));
1457 }
1458
1459 if (mTexStorage && mTexStorage->isRenderTarget())
1460 {
1461 for (int level = 1; level < levelCount; level++)
1462 {
1463 mTexStorage->generateMipmap(level);
1464
1465 mImageArray[level]->markClean();
1466 }
1467 }
1468 else
1469 {
1470 for (int level = 1; level < levelCount; level++)
1471 {
1472 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1473 }
1474 }
1475}
1476
1477unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1478{
1479 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1480}
1481
1482RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1483{
1484 // ensure the underlying texture is created
1485 if (!ensureRenderTarget())
1486 {
1487 return NULL;
1488 }
1489
1490 updateStorageLevel(level);
1491
1492 // ensure this is NOT a depth texture
1493 if (isDepth(level))
1494 {
1495 return NULL;
1496 }
1497
1498 return mTexStorage->getRenderTarget(level);
1499}
1500
1501RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1502{
1503 // ensure the underlying texture is created
1504 if (!ensureRenderTarget())
1505 {
1506 return NULL;
1507 }
1508
1509 updateStorage();
1510
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511 return mTexStorage->getRenderTarget(level, layer);
1512}
1513
1514void TextureD3D_3D::initializeStorage(bool renderTarget)
1515{
1516 // Only initialize the first time this texture is used as a render target or shader resource
1517 if (mTexStorage)
1518 {
1519 return;
1520 }
1521
1522 // do not attempt to create storage for nonexistant data
1523 if (!isLevelComplete(0))
1524 {
1525 return;
1526 }
1527
1528 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1529
1530 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1531 ASSERT(mTexStorage);
1532
1533 // flush image data to the storage
1534 updateStorage();
1535}
1536
1537TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1538{
1539 GLsizei width = getBaseLevelWidth();
1540 GLsizei height = getBaseLevelHeight();
1541 GLsizei depth = getBaseLevelDepth();
1542
1543 ASSERT(width > 0 && height > 0 && depth > 0);
1544
1545 // use existing storage level count, when previously specified by TexStorage*D
1546 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1547
1548 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1549}
1550
1551void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1552{
1553 SafeDelete(mTexStorage);
1554 mTexStorage = newCompleteTexStorage;
1555 mDirtyImages = true;
1556
1557 // We do not support managed 3D storage, as that is D3D9/ES2-only
1558 ASSERT(!mTexStorage->isManaged());
1559}
1560
1561void TextureD3D_3D::updateStorage()
1562{
1563 ASSERT(mTexStorage != NULL);
1564 GLint storageLevels = mTexStorage->getLevelCount();
1565 for (int level = 0; level < storageLevels; level++)
1566 {
1567 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1568 {
1569 updateStorageLevel(level);
1570 }
1571 }
1572}
1573
1574bool TextureD3D_3D::ensureRenderTarget()
1575{
1576 initializeStorage(true);
1577
1578 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1579 {
1580 ASSERT(mTexStorage);
1581 if (!mTexStorage->isRenderTarget())
1582 {
1583 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1584
1585 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1586 {
1587 delete newRenderTargetStorage;
1588 return gl::error(GL_OUT_OF_MEMORY, false);
1589 }
1590
1591 setCompleteTexStorage(newRenderTargetStorage);
1592 }
1593 }
1594
1595 return (mTexStorage && mTexStorage->isRenderTarget());
1596}
1597
1598TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1599{
1600 return mTexStorage;
1601}
1602
1603const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1604{
1605 return mImageArray[0];
1606}
1607
1608bool TextureD3D_3D::isValidLevel(int level) const
1609{
1610 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1611}
1612
1613bool TextureD3D_3D::isLevelComplete(int level) const
1614{
1615 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1616
1617 if (isImmutable())
1618 {
1619 return true;
1620 }
1621
1622 GLsizei width = getBaseLevelWidth();
1623 GLsizei height = getBaseLevelHeight();
1624 GLsizei depth = getBaseLevelDepth();
1625
1626 if (width <= 0 || height <= 0 || depth <= 0)
1627 {
1628 return false;
1629 }
1630
1631 if (level == 0)
1632 {
1633 return true;
1634 }
1635
1636 ImageD3D *levelImage = mImageArray[level];
1637
1638 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1639 {
1640 return false;
1641 }
1642
1643 if (levelImage->getWidth() != std::max(1, width >> level))
1644 {
1645 return false;
1646 }
1647
1648 if (levelImage->getHeight() != std::max(1, height >> level))
1649 {
1650 return false;
1651 }
1652
1653 if (levelImage->getDepth() != std::max(1, depth >> level))
1654 {
1655 return false;
1656 }
1657
1658 return true;
1659}
1660
1661void TextureD3D_3D::updateStorageLevel(int level)
1662{
1663 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1664 ASSERT(isLevelComplete(level));
1665
1666 if (mImageArray[level]->isDirty())
1667 {
1668 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1669 }
1670}
1671
1672void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1673{
1674 // If there currently is a corresponding storage texture image, it has these parameters
1675 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1676 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1677 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1678 const GLenum storageFormat = getBaseLevelInternalFormat();
1679
1680 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1681
1682 if (mTexStorage)
1683 {
1684 const int storageLevels = mTexStorage->getLevelCount();
1685
1686 if ((level >= storageLevels && storageLevels != 0) ||
1687 width != storageWidth ||
1688 height != storageHeight ||
1689 depth != storageDepth ||
1690 internalformat != storageFormat) // Discard mismatched storage
1691 {
1692 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1693 {
1694 mImageArray[i]->markDirty();
1695 }
1696
1697 SafeDelete(mTexStorage);
1698 mDirtyImages = true;
1699 }
1700 }
1701}
1702
1703void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1704{
1705 if (isValidLevel(level))
1706 {
1707 ImageD3D *image = mImageArray[level];
1708 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1709 {
1710 image->markClean();
1711 }
1712 }
1713}
1714
Brandon Jones142ec422014-07-16 10:31:30 -07001715
1716TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001717 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001718 mTexStorage(NULL)
1719{
1720 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1721 {
1722 mLayerCounts[level] = 0;
1723 mImageArray[level] = NULL;
1724 }
1725}
1726
1727TextureD3D_2DArray::~TextureD3D_2DArray()
1728{
Austin Kinross69822602014-08-12 15:51:37 -07001729 // Delete the Images before the TextureStorage.
1730 // Images might be relying on the TextureStorage for some of their data.
1731 // 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 -07001732 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001733 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001734}
1735
Brandon Jones142ec422014-07-16 10:31:30 -07001736Image *TextureD3D_2DArray::getImage(int level, int layer) const
1737{
1738 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1739 ASSERT(layer < mLayerCounts[level]);
1740 return mImageArray[level][layer];
1741}
1742
1743GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1744{
1745 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1746 return mLayerCounts[level];
1747}
1748
Brandon Jones142ec422014-07-16 10:31:30 -07001749GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1750{
1751 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1752}
1753
1754GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1755{
1756 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1757}
1758
1759GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1760{
1761 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1762}
1763
1764GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1765{
1766 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1767}
1768
1769bool TextureD3D_2DArray::isDepth(GLint level) const
1770{
Geoff Lang5d601382014-07-22 15:14:06 -04001771 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001772}
1773
Brandon Jonescef06ff2014-08-05 13:27:48 -07001774void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001775{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001776 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1777
Geoff Lang5d601382014-07-22 15:14:06 -04001778 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1779
Brandon Jones142ec422014-07-16 10:31:30 -07001780 redefineImage(level, sizedInternalFormat, width, height, depth);
1781
Geoff Lang5d601382014-07-22 15:14:06 -04001782 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1783 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001784
1785 for (int i = 0; i < depth; i++)
1786 {
1787 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1788 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1789 }
1790}
1791
Brandon Jonescef06ff2014-08-05 13:27:48 -07001792void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001793{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001794 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1795
Brandon Jones142ec422014-07-16 10:31:30 -07001796 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1797 redefineImage(level, format, width, height, depth);
1798
Geoff Lang5d601382014-07-22 15:14:06 -04001799 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1800 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001801
1802 for (int i = 0; i < depth; i++)
1803 {
1804 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1805 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1806 }
1807}
1808
Brandon Jonescef06ff2014-08-05 13:27:48 -07001809void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001810{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001811 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1812
Geoff Lang5d601382014-07-22 15:14:06 -04001813 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1814 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001815
1816 for (int i = 0; i < depth; i++)
1817 {
1818 int layer = zoffset + i;
1819 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1820
1821 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
1822 {
1823 commitRect(level, xoffset, yoffset, layer, width, height);
1824 }
1825 }
1826}
1827
Brandon Jonescef06ff2014-08-05 13:27:48 -07001828void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001829{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001830 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1831
Geoff Lang5d601382014-07-22 15:14:06 -04001832 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1833 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001834
1835 for (int i = 0; i < depth; i++)
1836 {
1837 int layer = zoffset + i;
1838 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1839
1840 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1841 {
1842 commitRect(level, xoffset, yoffset, layer, width, height);
1843 }
1844 }
1845}
1846
Brandon Jonescef06ff2014-08-05 13:27:48 -07001847void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1848{
1849 UNIMPLEMENTED();
1850}
1851
Brandon Jones142ec422014-07-16 10:31:30 -07001852void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1853{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001854 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1855
Brandon Jones142ec422014-07-16 10:31:30 -07001856 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1857 // the current level we're copying to is defined (with appropriate format, width & height)
1858 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1859
1860 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1861 {
1862 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1863 mDirtyImages = true;
1864 }
1865 else
1866 {
1867 ensureRenderTarget();
1868
1869 if (isValidLevel(level))
1870 {
1871 updateStorageLevel(level);
1872
1873 gl::Rectangle sourceRect;
1874 sourceRect.x = x;
1875 sourceRect.width = width;
1876 sourceRect.y = y;
1877 sourceRect.height = height;
1878
Geoff Lang5d601382014-07-22 15:14:06 -04001879 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001880 xoffset, yoffset, zoffset, mTexStorage, level);
1881 }
1882 }
1883}
1884
Brandon Jonescef06ff2014-08-05 13:27:48 -07001885void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001886{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001887 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1888
Brandon Jones142ec422014-07-16 10:31:30 -07001889 deleteImages();
1890
1891 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1892 {
1893 GLsizei levelWidth = std::max(1, width >> level);
1894 GLsizei levelHeight = std::max(1, height >> level);
1895
1896 mLayerCounts[level] = (level < levels ? depth : 0);
1897
1898 if (mLayerCounts[level] > 0)
1899 {
1900 // Create new images for this level
1901 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1902
1903 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1904 {
1905 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1906 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1907 levelHeight, 1, true);
1908 }
1909 }
1910 }
1911
1912 mImmutable = true;
1913 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1914}
1915
Brandon Jones6053a522014-07-25 16:22:09 -07001916void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001917{
Brandon Jones6053a522014-07-25 16:22:09 -07001918 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001919}
1920
Brandon Jones6053a522014-07-25 16:22:09 -07001921void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001922{
Brandon Jones6053a522014-07-25 16:22:09 -07001923 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001924}
1925
Brandon Jones6053a522014-07-25 16:22:09 -07001926
Brandon Jones142ec422014-07-16 10:31:30 -07001927void TextureD3D_2DArray::generateMipmaps()
1928{
1929 int baseWidth = getBaseLevelWidth();
1930 int baseHeight = getBaseLevelHeight();
1931 int baseDepth = getBaseLevelDepth();
1932 GLenum baseFormat = getBaseLevelInternalFormat();
1933
1934 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1935 int levelCount = mipLevels();
1936 for (int level = 1; level < levelCount; level++)
1937 {
1938 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1939 }
1940
1941 if (mTexStorage && mTexStorage->isRenderTarget())
1942 {
1943 for (int level = 1; level < levelCount; level++)
1944 {
1945 mTexStorage->generateMipmap(level);
1946
1947 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1948 {
1949 mImageArray[level][layer]->markClean();
1950 }
1951 }
1952 }
1953 else
1954 {
1955 for (int level = 1; level < levelCount; level++)
1956 {
1957 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1958 {
1959 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
1960 }
1961 }
1962 }
1963}
1964
1965unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
1966{
1967 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1968}
1969
1970RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
1971{
1972 // ensure the underlying texture is created
1973 if (!ensureRenderTarget())
1974 {
1975 return NULL;
1976 }
1977
1978 updateStorageLevel(level);
Brandon Jones142ec422014-07-16 10:31:30 -07001979 return mTexStorage->getRenderTarget(level, layer);
1980}
1981
1982void TextureD3D_2DArray::initializeStorage(bool renderTarget)
1983{
1984 // Only initialize the first time this texture is used as a render target or shader resource
1985 if (mTexStorage)
1986 {
1987 return;
1988 }
1989
1990 // do not attempt to create storage for nonexistant data
1991 if (!isLevelComplete(0))
1992 {
1993 return;
1994 }
1995
1996 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1997
1998 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1999 ASSERT(mTexStorage);
2000
2001 // flush image data to the storage
2002 updateStorage();
2003}
2004
2005TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2006{
2007 GLsizei width = getBaseLevelWidth();
2008 GLsizei height = getBaseLevelHeight();
2009 GLsizei depth = getLayers(0);
2010
2011 ASSERT(width > 0 && height > 0 && depth > 0);
2012
2013 // use existing storage level count, when previously specified by TexStorage*D
2014 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2015
2016 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2017}
2018
2019void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2020{
2021 SafeDelete(mTexStorage);
2022 mTexStorage = newCompleteTexStorage;
2023 mDirtyImages = true;
2024
2025 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2026 ASSERT(!mTexStorage->isManaged());
2027}
2028
2029void TextureD3D_2DArray::updateStorage()
2030{
2031 ASSERT(mTexStorage != NULL);
2032 GLint storageLevels = mTexStorage->getLevelCount();
2033 for (int level = 0; level < storageLevels; level++)
2034 {
2035 if (isLevelComplete(level))
2036 {
2037 updateStorageLevel(level);
2038 }
2039 }
2040}
2041
2042bool TextureD3D_2DArray::ensureRenderTarget()
2043{
2044 initializeStorage(true);
2045
2046 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2047 {
2048 ASSERT(mTexStorage);
2049 if (!mTexStorage->isRenderTarget())
2050 {
2051 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2052
2053 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2054 {
2055 delete newRenderTargetStorage;
2056 return gl::error(GL_OUT_OF_MEMORY, false);
2057 }
2058
2059 setCompleteTexStorage(newRenderTargetStorage);
2060 }
2061 }
2062
2063 return (mTexStorage && mTexStorage->isRenderTarget());
2064}
2065
2066const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2067{
2068 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2069}
2070
2071TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2072{
2073 return mTexStorage;
2074}
2075
2076bool TextureD3D_2DArray::isValidLevel(int level) const
2077{
2078 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2079}
2080
2081bool TextureD3D_2DArray::isLevelComplete(int level) const
2082{
2083 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2084
2085 if (isImmutable())
2086 {
2087 return true;
2088 }
2089
2090 GLsizei width = getBaseLevelWidth();
2091 GLsizei height = getBaseLevelHeight();
2092 GLsizei layers = getLayers(0);
2093
2094 if (width <= 0 || height <= 0 || layers <= 0)
2095 {
2096 return false;
2097 }
2098
2099 if (level == 0)
2100 {
2101 return true;
2102 }
2103
2104 if (getInternalFormat(level) != getInternalFormat(0))
2105 {
2106 return false;
2107 }
2108
2109 if (getWidth(level) != std::max(1, width >> level))
2110 {
2111 return false;
2112 }
2113
2114 if (getHeight(level) != std::max(1, height >> level))
2115 {
2116 return false;
2117 }
2118
2119 if (getLayers(level) != layers)
2120 {
2121 return false;
2122 }
2123
2124 return true;
2125}
2126
2127void TextureD3D_2DArray::updateStorageLevel(int level)
2128{
2129 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2130 ASSERT(isLevelComplete(level));
2131
2132 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2133 {
2134 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2135 if (mImageArray[level][layer]->isDirty())
2136 {
2137 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2138 }
2139 }
2140}
2141
2142void TextureD3D_2DArray::deleteImages()
2143{
2144 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2145 {
2146 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2147 {
2148 delete mImageArray[level][layer];
2149 }
2150 delete[] mImageArray[level];
2151 mImageArray[level] = NULL;
2152 mLayerCounts[level] = 0;
2153 }
2154}
2155
2156void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2157{
2158 // If there currently is a corresponding storage texture image, it has these parameters
2159 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2160 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2161 const int storageDepth = getLayers(0);
2162 const GLenum storageFormat = getBaseLevelInternalFormat();
2163
2164 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2165 {
2166 delete mImageArray[level][layer];
2167 }
2168 delete[] mImageArray[level];
2169 mImageArray[level] = NULL;
2170 mLayerCounts[level] = depth;
2171
2172 if (depth > 0)
2173 {
2174 mImageArray[level] = new ImageD3D*[depth]();
2175
2176 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2177 {
2178 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2179 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2180 }
2181 }
2182
2183 if (mTexStorage)
2184 {
2185 const int storageLevels = mTexStorage->getLevelCount();
2186
2187 if ((level >= storageLevels && storageLevels != 0) ||
2188 width != storageWidth ||
2189 height != storageHeight ||
2190 depth != storageDepth ||
2191 internalformat != storageFormat) // Discard mismatched storage
2192 {
2193 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2194 {
2195 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2196 {
2197 mImageArray[level][layer]->markDirty();
2198 }
2199 }
2200
2201 delete mTexStorage;
2202 mTexStorage = NULL;
2203 mDirtyImages = true;
2204 }
2205 }
2206}
2207
2208void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2209{
2210 if (isValidLevel(level) && layerTarget < getLayers(level))
2211 {
2212 ImageD3D *image = mImageArray[level][layerTarget];
2213 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2214 {
2215 image->markClean();
2216 }
2217 }
2218}
2219
Brandon Jones78b1acd2014-07-15 15:33:07 -07002220}