blob: d5e3ad85a31ddf159deb68f84e8029509841d2d4 [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);
521
522 // ensure this is NOT a depth texture
523 if (isDepth(level))
524 {
525 return NULL;
526 }
527
528 return mTexStorage->getRenderTarget(level);
529}
530
Brandon Jonescef06ff2014-08-05 13:27:48 -0700531RenderTarget *TextureD3D_2D::getDepthStencil(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700532{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700533 ASSERT(layer == 0);
534
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535 // ensure the underlying texture is created
536 if (!ensureRenderTarget())
537 {
538 return NULL;
539 }
540
541 updateStorageLevel(level);
542
543 // ensure this is actually a depth texture
544 if (!isDepth(level))
545 {
546 return NULL;
547 }
548
549 return mTexStorage->getRenderTarget(level);
550}
551
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552bool TextureD3D_2D::isValidLevel(int level) const
553{
554 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
555}
556
557bool TextureD3D_2D::isLevelComplete(int level) const
558{
559 if (isImmutable())
560 {
561 return true;
562 }
563
Brandon Jones78b1acd2014-07-15 15:33:07 -0700564 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700565
566 GLsizei width = baseImage->getWidth();
567 GLsizei height = baseImage->getHeight();
568
569 if (width <= 0 || height <= 0)
570 {
571 return false;
572 }
573
574 // The base image level is complete if the width and height are positive
575 if (level == 0)
576 {
577 return true;
578 }
579
580 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700581 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582
583 if (image->getInternalFormat() != baseImage->getInternalFormat())
584 {
585 return false;
586 }
587
588 if (image->getWidth() != std::max(1, width >> level))
589 {
590 return false;
591 }
592
593 if (image->getHeight() != std::max(1, height >> level))
594 {
595 return false;
596 }
597
598 return true;
599}
600
601// Constructs a native texture resource from the texture images
602void TextureD3D_2D::initializeStorage(bool renderTarget)
603{
604 // Only initialize the first time this texture is used as a render target or shader resource
605 if (mTexStorage)
606 {
607 return;
608 }
609
610 // do not attempt to create storage for nonexistant data
611 if (!isLevelComplete(0))
612 {
613 return;
614 }
615
616 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
617
618 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
619 ASSERT(mTexStorage);
620
621 // flush image data to the storage
622 updateStorage();
623}
624
Brandon Jones78b1acd2014-07-15 15:33:07 -0700625TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626{
627 GLsizei width = getBaseLevelWidth();
628 GLsizei height = getBaseLevelHeight();
629
630 ASSERT(width > 0 && height > 0);
631
632 // use existing storage level count, when previously specified by TexStorage*D
633 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
634
Brandon Jones78b1acd2014-07-15 15:33:07 -0700635 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636}
637
638void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
639{
640 SafeDelete(mTexStorage);
641 mTexStorage = newCompleteTexStorage;
642
643 if (mTexStorage && mTexStorage->isManaged())
644 {
645 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
646 {
647 mImageArray[level]->setManagedSurface(mTexStorage, level);
648 }
649 }
650
651 mDirtyImages = true;
652}
653
654void TextureD3D_2D::updateStorage()
655{
656 ASSERT(mTexStorage != NULL);
657 GLint storageLevels = mTexStorage->getLevelCount();
658 for (int level = 0; level < storageLevels; level++)
659 {
660 if (mImageArray[level]->isDirty() && isLevelComplete(level))
661 {
662 updateStorageLevel(level);
663 }
664 }
665}
666
667bool TextureD3D_2D::ensureRenderTarget()
668{
669 initializeStorage(true);
670
671 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
672 {
673 ASSERT(mTexStorage);
674 if (!mTexStorage->isRenderTarget())
675 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700676 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677
678 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
679 {
680 delete newRenderTargetStorage;
681 return gl::error(GL_OUT_OF_MEMORY, false);
682 }
683
684 setCompleteTexStorage(newRenderTargetStorage);
685 }
686 }
687
688 return (mTexStorage && mTexStorage->isRenderTarget());
689}
690
691TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
692{
693 return mTexStorage;
694}
695
696const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
697{
698 return mImageArray[0];
699}
700
701void TextureD3D_2D::updateStorageLevel(int level)
702{
703 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
704 ASSERT(isLevelComplete(level));
705
706 if (mImageArray[level]->isDirty())
707 {
708 commitRect(level, 0, 0, getWidth(level), getHeight(level));
709 }
710}
711
712void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
713{
714 // If there currently is a corresponding storage texture image, it has these parameters
715 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
716 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
717 const GLenum storageFormat = getBaseLevelInternalFormat();
718
719 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
720
721 if (mTexStorage)
722 {
723 const int storageLevels = mTexStorage->getLevelCount();
724
725 if ((level >= storageLevels && storageLevels != 0) ||
726 width != storageWidth ||
727 height != storageHeight ||
728 internalformat != storageFormat) // Discard mismatched storage
729 {
730 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
731 {
732 mImageArray[i]->markDirty();
733 }
734
735 SafeDelete(mTexStorage);
736 mDirtyImages = true;
737 }
738 }
739}
740
741void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
742{
743 if (isValidLevel(level))
744 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700745 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700746 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
747 {
748 image->markClean();
749 }
750 }
751}
752
Brandon Jones0511e802014-07-14 16:27:26 -0700753
Brandon Jones78b1acd2014-07-15 15:33:07 -0700754TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700755 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700756 mTexStorage(NULL)
757{
758 for (int i = 0; i < 6; i++)
759 {
760 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
761 {
762 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
763 }
764 }
765}
766
767TextureD3D_Cube::~TextureD3D_Cube()
768{
Austin Kinross69822602014-08-12 15:51:37 -0700769 // Delete the Images before the TextureStorage.
770 // Images might be relying on the TextureStorage for some of their data.
771 // 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 -0700772 for (int i = 0; i < 6; i++)
773 {
774 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
775 {
776 SafeDelete(mImageArray[i][j]);
777 }
778 }
Austin Kinross69822602014-08-12 15:51:37 -0700779
780 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700781}
782
Brandon Jonescef06ff2014-08-05 13:27:48 -0700783Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700784{
785 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700786 ASSERT(layer < 6);
787 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700788}
789
Brandon Jonescef06ff2014-08-05 13:27:48 -0700790GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700791{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
793 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700794}
795
Brandon Jonescef06ff2014-08-05 13:27:48 -0700796GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700797{
798 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700799 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700800 else
801 return GL_NONE;
802}
803
Brandon Jonescef06ff2014-08-05 13:27:48 -0700804bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700805{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700806 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700807}
808
Brandon Jonescef06ff2014-08-05 13:27:48 -0700809void 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 -0700810{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700811 ASSERT(depth == 1);
812
813 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400814 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700815
816 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
817
818 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
819}
820
Brandon Jonescef06ff2014-08-05 13:27:48 -0700821void 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 -0700822{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700823 ASSERT(depth == 1);
824
Brandon Jones0511e802014-07-14 16:27:26 -0700825 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700826 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
827
Brandon Jones0511e802014-07-14 16:27:26 -0700828 redefineImage(faceIndex, level, format, width, height);
829
830 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
831}
832
Brandon Jonescef06ff2014-08-05 13:27:48 -0700833void 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 -0700834{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700835 ASSERT(depth == 1 && zoffset == 0);
836
837 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
838
Brandon Jones0511e802014-07-14 16:27:26 -0700839 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
840 {
841 commitRect(faceIndex, level, xoffset, yoffset, width, height);
842 }
843}
844
Brandon Jonescef06ff2014-08-05 13:27:48 -0700845void 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 -0700846{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700847 ASSERT(depth == 1 && zoffset == 0);
848
849 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
850
Brandon Jones0511e802014-07-14 16:27:26 -0700851 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
852 {
853 commitRect(faceIndex, level, xoffset, yoffset, width, height);
854 }
855}
856
857void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
858{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700859 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400860 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
861
Brandon Jones0511e802014-07-14 16:27:26 -0700862 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
863
864 if (!mImageArray[faceIndex][level]->isRenderableFormat())
865 {
866 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
867 mDirtyImages = true;
868 }
869 else
870 {
871 ensureRenderTarget();
872 mImageArray[faceIndex][level]->markClean();
873
874 ASSERT(width == height);
875
876 if (width > 0 && isValidFaceLevel(faceIndex, level))
877 {
878 gl::Rectangle sourceRect;
879 sourceRect.x = x;
880 sourceRect.width = width;
881 sourceRect.y = y;
882 sourceRect.height = height;
883
884 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
885 }
886 }
887}
888
889void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
890{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700891 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700892
893 // We can only make our texture storage to a render target if the level we're copying *to* is complete
894 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
895 // rely on the "getBaseLevel*" methods reliably otherwise.
896 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
897
898 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
899 {
900 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
901 mDirtyImages = true;
902 }
903 else
904 {
905 ensureRenderTarget();
906
907 if (isValidFaceLevel(faceIndex, level))
908 {
909 updateStorageFaceLevel(faceIndex, level);
910
911 gl::Rectangle sourceRect;
912 sourceRect.x = x;
913 sourceRect.width = width;
914 sourceRect.y = y;
915 sourceRect.height = height;
916
Geoff Lang5d601382014-07-22 15:14:06 -0400917 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700918 xoffset, yoffset, mTexStorage, target, level);
919 }
920 }
921}
922
Brandon Jonescef06ff2014-08-05 13:27:48 -0700923void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700924{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700925 ASSERT(width == height);
926 ASSERT(depth == 1);
927
Brandon Jones0511e802014-07-14 16:27:26 -0700928 for (int level = 0; level < levels; level++)
929 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700930 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700931 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
932 {
933 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
934 }
935 }
936
937 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
938 {
939 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
940 {
941 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
942 }
943 }
944
945 mImmutable = true;
946
Brandon Jonescef06ff2014-08-05 13:27:48 -0700947 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700948}
949
Brandon Jones0511e802014-07-14 16:27:26 -0700950// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
951bool TextureD3D_Cube::isCubeComplete() const
952{
953 int baseWidth = getBaseLevelWidth();
954 int baseHeight = getBaseLevelHeight();
955 GLenum baseFormat = getBaseLevelInternalFormat();
956
957 if (baseWidth <= 0 || baseWidth != baseHeight)
958 {
959 return false;
960 }
961
962 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
963 {
964 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
965
966 if (faceBaseImage.getWidth() != baseWidth ||
967 faceBaseImage.getHeight() != baseHeight ||
968 faceBaseImage.getInternalFormat() != baseFormat )
969 {
970 return false;
971 }
972 }
973
974 return true;
975}
976
Brandon Jones6053a522014-07-25 16:22:09 -0700977void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
978{
979 UNREACHABLE();
980}
981
982void TextureD3D_Cube::releaseTexImage()
983{
984 UNREACHABLE();
985}
986
987
Brandon Jones0511e802014-07-14 16:27:26 -0700988void TextureD3D_Cube::generateMipmaps()
989{
990 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
991 int levelCount = mipLevels();
992 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
993 {
994 for (int level = 1; level < levelCount; level++)
995 {
996 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
997 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
998 }
999 }
1000
1001 if (mTexStorage && mTexStorage->isRenderTarget())
1002 {
1003 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1004 {
1005 for (int level = 1; level < levelCount; level++)
1006 {
1007 mTexStorage->generateMipmap(faceIndex, level);
1008
1009 mImageArray[faceIndex][level]->markClean();
1010 }
1011 }
1012 }
1013 else
1014 {
1015 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1016 {
1017 for (int level = 1; level < levelCount; level++)
1018 {
1019 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1020 }
1021 }
1022 }
1023}
1024
Brandon Jonescef06ff2014-08-05 13:27:48 -07001025unsigned int TextureD3D_Cube::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001026{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001027 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001028 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1029}
1030
Brandon Jonescef06ff2014-08-05 13:27:48 -07001031RenderTarget *TextureD3D_Cube::getRenderTarget(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001032{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001033 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001034 ASSERT(gl::IsCubemapTextureTarget(target));
1035
1036 // ensure the underlying texture is created
1037 if (!ensureRenderTarget())
1038 {
1039 return NULL;
1040 }
1041
Brandon Jonescef06ff2014-08-05 13:27:48 -07001042 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001043
1044 // ensure this is NOT a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001045 if (isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001046 {
1047 return NULL;
1048 }
1049
1050 return mTexStorage->getRenderTarget(target, level);
1051}
1052
Brandon Jonescef06ff2014-08-05 13:27:48 -07001053RenderTarget *TextureD3D_Cube::getDepthStencil(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001054{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001055 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001056 ASSERT(gl::IsCubemapTextureTarget(target));
1057
1058 // ensure the underlying texture is created
1059 if (!ensureRenderTarget())
1060 {
1061 return NULL;
1062 }
1063
Brandon Jonescef06ff2014-08-05 13:27:48 -07001064 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001065
1066 // ensure this is a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001067 if (!isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001068 {
1069 return NULL;
1070 }
1071
1072 return mTexStorage->getRenderTarget(target, level);
1073}
1074
Brandon Jones0511e802014-07-14 16:27:26 -07001075void TextureD3D_Cube::initializeStorage(bool renderTarget)
1076{
1077 // Only initialize the first time this texture is used as a render target or shader resource
1078 if (mTexStorage)
1079 {
1080 return;
1081 }
1082
1083 // do not attempt to create storage for nonexistant data
1084 if (!isFaceLevelComplete(0, 0))
1085 {
1086 return;
1087 }
1088
1089 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1090
1091 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1092 ASSERT(mTexStorage);
1093
1094 // flush image data to the storage
1095 updateStorage();
1096}
1097
1098TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1099{
1100 GLsizei size = getBaseLevelWidth();
1101
1102 ASSERT(size > 0);
1103
1104 // use existing storage level count, when previously specified by TexStorage*D
1105 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1106
1107 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1108}
1109
1110void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1111{
1112 SafeDelete(mTexStorage);
1113 mTexStorage = newCompleteTexStorage;
1114
1115 if (mTexStorage && mTexStorage->isManaged())
1116 {
1117 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1118 {
1119 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1120 {
1121 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1122 }
1123 }
1124 }
1125
1126 mDirtyImages = true;
1127}
1128
1129void TextureD3D_Cube::updateStorage()
1130{
1131 ASSERT(mTexStorage != NULL);
1132 GLint storageLevels = mTexStorage->getLevelCount();
1133 for (int face = 0; face < 6; face++)
1134 {
1135 for (int level = 0; level < storageLevels; level++)
1136 {
1137 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1138 {
1139 updateStorageFaceLevel(face, level);
1140 }
1141 }
1142 }
1143}
1144
1145bool TextureD3D_Cube::ensureRenderTarget()
1146{
1147 initializeStorage(true);
1148
1149 if (getBaseLevelWidth() > 0)
1150 {
1151 ASSERT(mTexStorage);
1152 if (!mTexStorage->isRenderTarget())
1153 {
1154 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1155
1156 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1157 {
1158 delete newRenderTargetStorage;
1159 return gl::error(GL_OUT_OF_MEMORY, false);
1160 }
1161
1162 setCompleteTexStorage(newRenderTargetStorage);
1163 }
1164 }
1165
1166 return (mTexStorage && mTexStorage->isRenderTarget());
1167}
1168
1169TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1170{
1171 return mTexStorage;
1172}
1173
1174const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1175{
1176 // Note: if we are not cube-complete, there is no single base level image that can describe all
1177 // cube faces, so this method is only well-defined for a cube-complete base level.
1178 return mImageArray[0][0];
1179}
1180
Brandon Jones0511e802014-07-14 16:27:26 -07001181bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1182{
1183 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1184}
1185
Brandon Jones0511e802014-07-14 16:27:26 -07001186bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1187{
1188 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1189
1190 if (isImmutable())
1191 {
1192 return true;
1193 }
1194
1195 int baseSize = getBaseLevelWidth();
1196
1197 if (baseSize <= 0)
1198 {
1199 return false;
1200 }
1201
1202 // "isCubeComplete" checks for base level completeness and we must call that
1203 // to determine if any face at level 0 is complete. We omit that check here
1204 // to avoid re-checking cube-completeness for every face at level 0.
1205 if (level == 0)
1206 {
1207 return true;
1208 }
1209
1210 // Check that non-zero levels are consistent with the base level.
1211 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1212
1213 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1214 {
1215 return false;
1216 }
1217
1218 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1219 {
1220 return false;
1221 }
1222
1223 return true;
1224}
1225
1226void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1227{
1228 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1229 ImageD3D *image = mImageArray[faceIndex][level];
1230
1231 if (image->isDirty())
1232 {
1233 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1234 }
1235}
1236
1237void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1238{
1239 // If there currently is a corresponding storage texture image, it has these parameters
1240 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1241 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1242 const GLenum storageFormat = getBaseLevelInternalFormat();
1243
1244 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1245
1246 if (mTexStorage)
1247 {
1248 const int storageLevels = mTexStorage->getLevelCount();
1249
1250 if ((level >= storageLevels && storageLevels != 0) ||
1251 width != storageWidth ||
1252 height != storageHeight ||
1253 internalformat != storageFormat) // Discard mismatched storage
1254 {
1255 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1256 {
1257 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1258 {
1259 mImageArray[faceIndex][level]->markDirty();
1260 }
1261 }
1262
1263 SafeDelete(mTexStorage);
1264
1265 mDirtyImages = true;
1266 }
1267 }
1268}
1269
1270void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1271{
1272 if (isValidFaceLevel(faceIndex, level))
1273 {
1274 ImageD3D *image = mImageArray[faceIndex][level];
1275 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1276 image->markClean();
1277 }
1278}
1279
Brandon Jones78b1acd2014-07-15 15:33:07 -07001280
1281TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001282 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001283 mTexStorage(NULL)
1284{
1285 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1286 {
1287 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1288 }
1289}
1290
1291TextureD3D_3D::~TextureD3D_3D()
1292{
Austin Kinross69822602014-08-12 15:51:37 -07001293 // Delete the Images before the TextureStorage.
1294 // Images might be relying on the TextureStorage for some of their data.
1295 // 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 -07001296 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1297 {
1298 delete mImageArray[i];
1299 }
Austin Kinross69822602014-08-12 15:51:37 -07001300
1301 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001302}
1303
Brandon Jonescef06ff2014-08-05 13:27:48 -07001304Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001305{
1306 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001307 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001308 return mImageArray[level];
1309}
1310
Brandon Jonescef06ff2014-08-05 13:27:48 -07001311GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001312{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001313 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1314 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001315}
1316
Brandon Jones78b1acd2014-07-15 15:33:07 -07001317GLsizei TextureD3D_3D::getWidth(GLint level) const
1318{
1319 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1320 return mImageArray[level]->getWidth();
1321 else
1322 return 0;
1323}
1324
1325GLsizei TextureD3D_3D::getHeight(GLint level) const
1326{
1327 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1328 return mImageArray[level]->getHeight();
1329 else
1330 return 0;
1331}
1332
1333GLsizei TextureD3D_3D::getDepth(GLint level) const
1334{
1335 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1336 return mImageArray[level]->getDepth();
1337 else
1338 return 0;
1339}
1340
1341GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1342{
1343 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1344 return mImageArray[level]->getInternalFormat();
1345 else
1346 return GL_NONE;
1347}
1348
1349bool TextureD3D_3D::isDepth(GLint level) const
1350{
Geoff Lang5d601382014-07-22 15:14:06 -04001351 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001352}
1353
Brandon Jonescef06ff2014-08-05 13:27:48 -07001354void 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 -07001355{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001356 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001357 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1358
Brandon Jones78b1acd2014-07-15 15:33:07 -07001359 redefineImage(level, sizedInternalFormat, width, height, depth);
1360
1361 bool fastUnpacked = false;
1362
1363 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1364 if (isFastUnpackable(unpack, sizedInternalFormat))
1365 {
1366 // Will try to create RT storage if it does not exist
1367 RenderTarget *destRenderTarget = getRenderTarget(level);
1368 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1369
1370 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1371 {
1372 // Ensure we don't overwrite our newly initialized data
1373 mImageArray[level]->markClean();
1374
1375 fastUnpacked = true;
1376 }
1377 }
1378
1379 if (!fastUnpacked)
1380 {
1381 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1382 }
1383}
1384
Brandon Jonescef06ff2014-08-05 13:27:48 -07001385void 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 -07001386{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001387 ASSERT(target == GL_TEXTURE_3D);
1388
Brandon Jones78b1acd2014-07-15 15:33:07 -07001389 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1390 redefineImage(level, format, width, height, depth);
1391
1392 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1393}
1394
Brandon Jonescef06ff2014-08-05 13:27:48 -07001395void 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 -07001396{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001397 ASSERT(target == GL_TEXTURE_3D);
1398
Brandon Jones78b1acd2014-07-15 15:33:07 -07001399 bool fastUnpacked = false;
1400
1401 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1402 if (isFastUnpackable(unpack, getInternalFormat(level)))
1403 {
1404 RenderTarget *destRenderTarget = getRenderTarget(level);
1405 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1406
1407 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1408 {
1409 // Ensure we don't overwrite our newly initialized data
1410 mImageArray[level]->markClean();
1411
1412 fastUnpacked = true;
1413 }
1414 }
1415
1416 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1417 {
1418 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1419 }
1420}
1421
Brandon Jonescef06ff2014-08-05 13:27:48 -07001422void 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 -07001423{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001424 ASSERT(target == GL_TEXTURE_3D);
1425
Brandon Jones78b1acd2014-07-15 15:33:07 -07001426 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1427 {
1428 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1429 }
1430}
1431
Brandon Jonescef06ff2014-08-05 13:27:48 -07001432void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1433{
1434 UNIMPLEMENTED();
1435}
1436
Brandon Jones78b1acd2014-07-15 15:33:07 -07001437void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1438{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001439 ASSERT(target == GL_TEXTURE_3D);
1440
Brandon Jones78b1acd2014-07-15 15:33:07 -07001441 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1442 // the current level we're copying to is defined (with appropriate format, width & height)
1443 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1444
1445 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1446 {
1447 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1448 mDirtyImages = true;
1449 }
1450 else
1451 {
1452 ensureRenderTarget();
1453
1454 if (isValidLevel(level))
1455 {
1456 updateStorageLevel(level);
1457
1458 gl::Rectangle sourceRect;
1459 sourceRect.x = x;
1460 sourceRect.width = width;
1461 sourceRect.y = y;
1462 sourceRect.height = height;
1463
1464 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001465 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001466 xoffset, yoffset, zoffset, mTexStorage, level);
1467 }
1468 }
1469}
1470
Brandon Jonescef06ff2014-08-05 13:27:48 -07001471void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001472{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001473 ASSERT(target == GL_TEXTURE_3D);
1474
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475 for (int level = 0; level < levels; level++)
1476 {
1477 GLsizei levelWidth = std::max(1, width >> level);
1478 GLsizei levelHeight = std::max(1, height >> level);
1479 GLsizei levelDepth = std::max(1, depth >> level);
1480 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1481 }
1482
1483 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1484 {
1485 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1486 }
1487
1488 mImmutable = true;
1489
1490 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1491}
1492
Brandon Jones6053a522014-07-25 16:22:09 -07001493void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001494{
Brandon Jones6053a522014-07-25 16:22:09 -07001495 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001496}
1497
Brandon Jones6053a522014-07-25 16:22:09 -07001498void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001499{
Brandon Jones6053a522014-07-25 16:22:09 -07001500 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001501}
1502
Brandon Jones6053a522014-07-25 16:22:09 -07001503
Brandon Jones78b1acd2014-07-15 15:33:07 -07001504void TextureD3D_3D::generateMipmaps()
1505{
1506 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1507 int levelCount = mipLevels();
1508 for (int level = 1; level < levelCount; level++)
1509 {
1510 redefineImage(level, getBaseLevelInternalFormat(),
1511 std::max(getBaseLevelWidth() >> level, 1),
1512 std::max(getBaseLevelHeight() >> level, 1),
1513 std::max(getBaseLevelDepth() >> level, 1));
1514 }
1515
1516 if (mTexStorage && mTexStorage->isRenderTarget())
1517 {
1518 for (int level = 1; level < levelCount; level++)
1519 {
1520 mTexStorage->generateMipmap(level);
1521
1522 mImageArray[level]->markClean();
1523 }
1524 }
1525 else
1526 {
1527 for (int level = 1; level < levelCount; level++)
1528 {
1529 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1530 }
1531 }
1532}
1533
1534unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1535{
1536 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1537}
1538
1539RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1540{
1541 // ensure the underlying texture is created
1542 if (!ensureRenderTarget())
1543 {
1544 return NULL;
1545 }
1546
1547 updateStorageLevel(level);
1548
1549 // ensure this is NOT a depth texture
1550 if (isDepth(level))
1551 {
1552 return NULL;
1553 }
1554
1555 return mTexStorage->getRenderTarget(level);
1556}
1557
1558RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1559{
1560 // ensure the underlying texture is created
1561 if (!ensureRenderTarget())
1562 {
1563 return NULL;
1564 }
1565
1566 updateStorage();
1567
1568 // ensure this is NOT a depth texture
1569 if (isDepth(level))
1570 {
1571 return NULL;
1572 }
1573
1574 return mTexStorage->getRenderTarget(level, layer);
1575}
1576
1577RenderTarget *TextureD3D_3D::getDepthStencil(GLint level, GLint layer)
1578{
1579 // ensure the underlying texture is created
1580 if (!ensureRenderTarget())
1581 {
1582 return NULL;
1583 }
1584
1585 updateStorageLevel(level);
1586
1587 // ensure this is a depth texture
1588 if (!isDepth(level))
1589 {
1590 return NULL;
1591 }
1592
1593 return mTexStorage->getRenderTarget(level, layer);
1594}
1595
1596void TextureD3D_3D::initializeStorage(bool renderTarget)
1597{
1598 // Only initialize the first time this texture is used as a render target or shader resource
1599 if (mTexStorage)
1600 {
1601 return;
1602 }
1603
1604 // do not attempt to create storage for nonexistant data
1605 if (!isLevelComplete(0))
1606 {
1607 return;
1608 }
1609
1610 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1611
1612 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1613 ASSERT(mTexStorage);
1614
1615 // flush image data to the storage
1616 updateStorage();
1617}
1618
1619TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1620{
1621 GLsizei width = getBaseLevelWidth();
1622 GLsizei height = getBaseLevelHeight();
1623 GLsizei depth = getBaseLevelDepth();
1624
1625 ASSERT(width > 0 && height > 0 && depth > 0);
1626
1627 // use existing storage level count, when previously specified by TexStorage*D
1628 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1629
1630 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1631}
1632
1633void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1634{
1635 SafeDelete(mTexStorage);
1636 mTexStorage = newCompleteTexStorage;
1637 mDirtyImages = true;
1638
1639 // We do not support managed 3D storage, as that is D3D9/ES2-only
1640 ASSERT(!mTexStorage->isManaged());
1641}
1642
1643void TextureD3D_3D::updateStorage()
1644{
1645 ASSERT(mTexStorage != NULL);
1646 GLint storageLevels = mTexStorage->getLevelCount();
1647 for (int level = 0; level < storageLevels; level++)
1648 {
1649 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1650 {
1651 updateStorageLevel(level);
1652 }
1653 }
1654}
1655
1656bool TextureD3D_3D::ensureRenderTarget()
1657{
1658 initializeStorage(true);
1659
1660 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1661 {
1662 ASSERT(mTexStorage);
1663 if (!mTexStorage->isRenderTarget())
1664 {
1665 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1666
1667 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1668 {
1669 delete newRenderTargetStorage;
1670 return gl::error(GL_OUT_OF_MEMORY, false);
1671 }
1672
1673 setCompleteTexStorage(newRenderTargetStorage);
1674 }
1675 }
1676
1677 return (mTexStorage && mTexStorage->isRenderTarget());
1678}
1679
1680TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1681{
1682 return mTexStorage;
1683}
1684
1685const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1686{
1687 return mImageArray[0];
1688}
1689
1690bool TextureD3D_3D::isValidLevel(int level) const
1691{
1692 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1693}
1694
1695bool TextureD3D_3D::isLevelComplete(int level) const
1696{
1697 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1698
1699 if (isImmutable())
1700 {
1701 return true;
1702 }
1703
1704 GLsizei width = getBaseLevelWidth();
1705 GLsizei height = getBaseLevelHeight();
1706 GLsizei depth = getBaseLevelDepth();
1707
1708 if (width <= 0 || height <= 0 || depth <= 0)
1709 {
1710 return false;
1711 }
1712
1713 if (level == 0)
1714 {
1715 return true;
1716 }
1717
1718 ImageD3D *levelImage = mImageArray[level];
1719
1720 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1721 {
1722 return false;
1723 }
1724
1725 if (levelImage->getWidth() != std::max(1, width >> level))
1726 {
1727 return false;
1728 }
1729
1730 if (levelImage->getHeight() != std::max(1, height >> level))
1731 {
1732 return false;
1733 }
1734
1735 if (levelImage->getDepth() != std::max(1, depth >> level))
1736 {
1737 return false;
1738 }
1739
1740 return true;
1741}
1742
1743void TextureD3D_3D::updateStorageLevel(int level)
1744{
1745 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1746 ASSERT(isLevelComplete(level));
1747
1748 if (mImageArray[level]->isDirty())
1749 {
1750 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1751 }
1752}
1753
1754void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1755{
1756 // If there currently is a corresponding storage texture image, it has these parameters
1757 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1758 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1759 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1760 const GLenum storageFormat = getBaseLevelInternalFormat();
1761
1762 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1763
1764 if (mTexStorage)
1765 {
1766 const int storageLevels = mTexStorage->getLevelCount();
1767
1768 if ((level >= storageLevels && storageLevels != 0) ||
1769 width != storageWidth ||
1770 height != storageHeight ||
1771 depth != storageDepth ||
1772 internalformat != storageFormat) // Discard mismatched storage
1773 {
1774 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1775 {
1776 mImageArray[i]->markDirty();
1777 }
1778
1779 SafeDelete(mTexStorage);
1780 mDirtyImages = true;
1781 }
1782 }
1783}
1784
1785void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1786{
1787 if (isValidLevel(level))
1788 {
1789 ImageD3D *image = mImageArray[level];
1790 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1791 {
1792 image->markClean();
1793 }
1794 }
1795}
1796
Brandon Jones142ec422014-07-16 10:31:30 -07001797
1798TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001799 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001800 mTexStorage(NULL)
1801{
1802 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1803 {
1804 mLayerCounts[level] = 0;
1805 mImageArray[level] = NULL;
1806 }
1807}
1808
1809TextureD3D_2DArray::~TextureD3D_2DArray()
1810{
Austin Kinross69822602014-08-12 15:51:37 -07001811 // Delete the Images before the TextureStorage.
1812 // Images might be relying on the TextureStorage for some of their data.
1813 // 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 -07001814 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001815 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001816}
1817
Brandon Jones142ec422014-07-16 10:31:30 -07001818Image *TextureD3D_2DArray::getImage(int level, int layer) const
1819{
1820 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1821 ASSERT(layer < mLayerCounts[level]);
1822 return mImageArray[level][layer];
1823}
1824
1825GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1826{
1827 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1828 return mLayerCounts[level];
1829}
1830
Brandon Jones142ec422014-07-16 10:31:30 -07001831GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1832{
1833 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1834}
1835
1836GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1837{
1838 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1839}
1840
1841GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1842{
1843 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1844}
1845
1846GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1847{
1848 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1849}
1850
1851bool TextureD3D_2DArray::isDepth(GLint level) const
1852{
Geoff Lang5d601382014-07-22 15:14:06 -04001853 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001854}
1855
Brandon Jonescef06ff2014-08-05 13:27:48 -07001856void 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 -07001857{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001858 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1859
Geoff Lang5d601382014-07-22 15:14:06 -04001860 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1861
Brandon Jones142ec422014-07-16 10:31:30 -07001862 redefineImage(level, sizedInternalFormat, width, height, depth);
1863
Geoff Lang5d601382014-07-22 15:14:06 -04001864 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1865 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001866
1867 for (int i = 0; i < depth; i++)
1868 {
1869 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1870 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1871 }
1872}
1873
Brandon Jonescef06ff2014-08-05 13:27:48 -07001874void 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 -07001875{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001876 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1877
Brandon Jones142ec422014-07-16 10:31:30 -07001878 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1879 redefineImage(level, format, width, height, depth);
1880
Geoff Lang5d601382014-07-22 15:14:06 -04001881 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1882 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001883
1884 for (int i = 0; i < depth; i++)
1885 {
1886 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1887 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1888 }
1889}
1890
Brandon Jonescef06ff2014-08-05 13:27:48 -07001891void 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 -07001892{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001893 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1894
Geoff Lang5d601382014-07-22 15:14:06 -04001895 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1896 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001897
1898 for (int i = 0; i < depth; i++)
1899 {
1900 int layer = zoffset + i;
1901 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1902
1903 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
1904 {
1905 commitRect(level, xoffset, yoffset, layer, width, height);
1906 }
1907 }
1908}
1909
Brandon Jonescef06ff2014-08-05 13:27:48 -07001910void 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 -07001911{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001912 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1913
Geoff Lang5d601382014-07-22 15:14:06 -04001914 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1915 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001916
1917 for (int i = 0; i < depth; i++)
1918 {
1919 int layer = zoffset + i;
1920 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1921
1922 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1923 {
1924 commitRect(level, xoffset, yoffset, layer, width, height);
1925 }
1926 }
1927}
1928
Brandon Jonescef06ff2014-08-05 13:27:48 -07001929void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1930{
1931 UNIMPLEMENTED();
1932}
1933
Brandon Jones142ec422014-07-16 10:31:30 -07001934void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1935{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001936 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1937
Brandon Jones142ec422014-07-16 10:31:30 -07001938 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1939 // the current level we're copying to is defined (with appropriate format, width & height)
1940 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1941
1942 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1943 {
1944 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1945 mDirtyImages = true;
1946 }
1947 else
1948 {
1949 ensureRenderTarget();
1950
1951 if (isValidLevel(level))
1952 {
1953 updateStorageLevel(level);
1954
1955 gl::Rectangle sourceRect;
1956 sourceRect.x = x;
1957 sourceRect.width = width;
1958 sourceRect.y = y;
1959 sourceRect.height = height;
1960
Geoff Lang5d601382014-07-22 15:14:06 -04001961 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001962 xoffset, yoffset, zoffset, mTexStorage, level);
1963 }
1964 }
1965}
1966
Brandon Jonescef06ff2014-08-05 13:27:48 -07001967void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001968{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001969 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1970
Brandon Jones142ec422014-07-16 10:31:30 -07001971 deleteImages();
1972
1973 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1974 {
1975 GLsizei levelWidth = std::max(1, width >> level);
1976 GLsizei levelHeight = std::max(1, height >> level);
1977
1978 mLayerCounts[level] = (level < levels ? depth : 0);
1979
1980 if (mLayerCounts[level] > 0)
1981 {
1982 // Create new images for this level
1983 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1984
1985 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1986 {
1987 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1988 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1989 levelHeight, 1, true);
1990 }
1991 }
1992 }
1993
1994 mImmutable = true;
1995 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1996}
1997
Brandon Jones6053a522014-07-25 16:22:09 -07001998void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001999{
Brandon Jones6053a522014-07-25 16:22:09 -07002000 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002001}
2002
Brandon Jones6053a522014-07-25 16:22:09 -07002003void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002004{
Brandon Jones6053a522014-07-25 16:22:09 -07002005 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002006}
2007
Brandon Jones6053a522014-07-25 16:22:09 -07002008
Brandon Jones142ec422014-07-16 10:31:30 -07002009void TextureD3D_2DArray::generateMipmaps()
2010{
2011 int baseWidth = getBaseLevelWidth();
2012 int baseHeight = getBaseLevelHeight();
2013 int baseDepth = getBaseLevelDepth();
2014 GLenum baseFormat = getBaseLevelInternalFormat();
2015
2016 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2017 int levelCount = mipLevels();
2018 for (int level = 1; level < levelCount; level++)
2019 {
2020 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2021 }
2022
2023 if (mTexStorage && mTexStorage->isRenderTarget())
2024 {
2025 for (int level = 1; level < levelCount; level++)
2026 {
2027 mTexStorage->generateMipmap(level);
2028
2029 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2030 {
2031 mImageArray[level][layer]->markClean();
2032 }
2033 }
2034 }
2035 else
2036 {
2037 for (int level = 1; level < levelCount; level++)
2038 {
2039 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2040 {
2041 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2042 }
2043 }
2044 }
2045}
2046
2047unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2048{
2049 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2050}
2051
2052RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2053{
2054 // ensure the underlying texture is created
2055 if (!ensureRenderTarget())
2056 {
2057 return NULL;
2058 }
2059
2060 updateStorageLevel(level);
2061
2062 // ensure this is NOT a depth texture
2063 if (isDepth(level))
2064 {
2065 return NULL;
2066 }
2067
2068 return mTexStorage->getRenderTarget(level, layer);
2069}
2070
2071RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer)
2072{
2073 // ensure the underlying texture is created
2074 if (!ensureRenderTarget())
2075 {
2076 return NULL;
2077 }
2078
2079 updateStorageLevel(level);
2080
2081 // ensure this is a depth texture
2082 if (!isDepth(level))
2083 {
2084 return NULL;
2085 }
2086
2087 return mTexStorage->getRenderTarget(level, layer);
2088}
2089
2090void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2091{
2092 // Only initialize the first time this texture is used as a render target or shader resource
2093 if (mTexStorage)
2094 {
2095 return;
2096 }
2097
2098 // do not attempt to create storage for nonexistant data
2099 if (!isLevelComplete(0))
2100 {
2101 return;
2102 }
2103
2104 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2105
2106 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2107 ASSERT(mTexStorage);
2108
2109 // flush image data to the storage
2110 updateStorage();
2111}
2112
2113TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2114{
2115 GLsizei width = getBaseLevelWidth();
2116 GLsizei height = getBaseLevelHeight();
2117 GLsizei depth = getLayers(0);
2118
2119 ASSERT(width > 0 && height > 0 && depth > 0);
2120
2121 // use existing storage level count, when previously specified by TexStorage*D
2122 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2123
2124 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2125}
2126
2127void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2128{
2129 SafeDelete(mTexStorage);
2130 mTexStorage = newCompleteTexStorage;
2131 mDirtyImages = true;
2132
2133 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2134 ASSERT(!mTexStorage->isManaged());
2135}
2136
2137void TextureD3D_2DArray::updateStorage()
2138{
2139 ASSERT(mTexStorage != NULL);
2140 GLint storageLevels = mTexStorage->getLevelCount();
2141 for (int level = 0; level < storageLevels; level++)
2142 {
2143 if (isLevelComplete(level))
2144 {
2145 updateStorageLevel(level);
2146 }
2147 }
2148}
2149
2150bool TextureD3D_2DArray::ensureRenderTarget()
2151{
2152 initializeStorage(true);
2153
2154 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2155 {
2156 ASSERT(mTexStorage);
2157 if (!mTexStorage->isRenderTarget())
2158 {
2159 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2160
2161 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2162 {
2163 delete newRenderTargetStorage;
2164 return gl::error(GL_OUT_OF_MEMORY, false);
2165 }
2166
2167 setCompleteTexStorage(newRenderTargetStorage);
2168 }
2169 }
2170
2171 return (mTexStorage && mTexStorage->isRenderTarget());
2172}
2173
2174const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2175{
2176 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2177}
2178
2179TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2180{
2181 return mTexStorage;
2182}
2183
2184bool TextureD3D_2DArray::isValidLevel(int level) const
2185{
2186 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2187}
2188
2189bool TextureD3D_2DArray::isLevelComplete(int level) const
2190{
2191 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2192
2193 if (isImmutable())
2194 {
2195 return true;
2196 }
2197
2198 GLsizei width = getBaseLevelWidth();
2199 GLsizei height = getBaseLevelHeight();
2200 GLsizei layers = getLayers(0);
2201
2202 if (width <= 0 || height <= 0 || layers <= 0)
2203 {
2204 return false;
2205 }
2206
2207 if (level == 0)
2208 {
2209 return true;
2210 }
2211
2212 if (getInternalFormat(level) != getInternalFormat(0))
2213 {
2214 return false;
2215 }
2216
2217 if (getWidth(level) != std::max(1, width >> level))
2218 {
2219 return false;
2220 }
2221
2222 if (getHeight(level) != std::max(1, height >> level))
2223 {
2224 return false;
2225 }
2226
2227 if (getLayers(level) != layers)
2228 {
2229 return false;
2230 }
2231
2232 return true;
2233}
2234
2235void TextureD3D_2DArray::updateStorageLevel(int level)
2236{
2237 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2238 ASSERT(isLevelComplete(level));
2239
2240 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2241 {
2242 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2243 if (mImageArray[level][layer]->isDirty())
2244 {
2245 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2246 }
2247 }
2248}
2249
2250void TextureD3D_2DArray::deleteImages()
2251{
2252 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2253 {
2254 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2255 {
2256 delete mImageArray[level][layer];
2257 }
2258 delete[] mImageArray[level];
2259 mImageArray[level] = NULL;
2260 mLayerCounts[level] = 0;
2261 }
2262}
2263
2264void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2265{
2266 // If there currently is a corresponding storage texture image, it has these parameters
2267 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2268 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2269 const int storageDepth = getLayers(0);
2270 const GLenum storageFormat = getBaseLevelInternalFormat();
2271
2272 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2273 {
2274 delete mImageArray[level][layer];
2275 }
2276 delete[] mImageArray[level];
2277 mImageArray[level] = NULL;
2278 mLayerCounts[level] = depth;
2279
2280 if (depth > 0)
2281 {
2282 mImageArray[level] = new ImageD3D*[depth]();
2283
2284 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2285 {
2286 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2287 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2288 }
2289 }
2290
2291 if (mTexStorage)
2292 {
2293 const int storageLevels = mTexStorage->getLevelCount();
2294
2295 if ((level >= storageLevels && storageLevels != 0) ||
2296 width != storageWidth ||
2297 height != storageHeight ||
2298 depth != storageDepth ||
2299 internalformat != storageFormat) // Discard mismatched storage
2300 {
2301 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2302 {
2303 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2304 {
2305 mImageArray[level][layer]->markDirty();
2306 }
2307 }
2308
2309 delete mTexStorage;
2310 mTexStorage = NULL;
2311 mDirtyImages = true;
2312 }
2313 }
2314}
2315
2316void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2317{
2318 if (isValidLevel(level) && layerTarget < getLayers(level))
2319 {
2320 ImageD3D *image = mImageArray[level][layerTarget];
2321 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2322 {
2323 image->markClean();
2324 }
2325 }
2326}
2327
Brandon Jones78b1acd2014-07-15 15:33:07 -07002328}