blob: 06803eafa19ed53db38e61e13cbda710f47122e9 [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,
Jamie Madillfeda4d22014-09-17 13:03:29 -0400124 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
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 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400141 Image *image = getImage(index);
142 ASSERT(image);
143
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
145 mDirtyImages = true;
146 }
147
148 return true;
149}
150
Brandon Jones78b1acd2014-07-15 15:33:07 -0700151void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152{
153 if (pixels != NULL)
154 {
155 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
156 mDirtyImages = true;
157 }
158}
159
160bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700161 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162{
163 if (pixels != NULL)
164 {
165 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
166 mDirtyImages = true;
167 }
168
169 return true;
170}
171
172bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
173{
174 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
175}
176
177bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700178 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700179{
180 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
181 {
182 return true;
183 }
184
185 // In order to perform the fast copy through the shader, we must have the right format, and be able
186 // to create a render target.
187 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
188
189 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
190
191 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
192}
193
194GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
195{
196 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
197 {
198 // Maximum number of levels
199 return gl::log2(std::max(std::max(width, height), depth)) + 1;
200 }
201 else
202 {
203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
204 return 1;
205 }
206}
207
208int TextureD3D::mipLevels() const
209{
210 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
211}
212
213
Brandon Jones78b1acd2014-07-15 15:33:07 -0700214TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700215 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700216 mTexStorage(NULL)
217{
218 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
219 {
220 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
221 }
222}
223
224TextureD3D_2D::~TextureD3D_2D()
225{
Austin Kinross69822602014-08-12 15:51:37 -0700226 // Delete the Images before the TextureStorage.
227 // Images might be relying on the TextureStorage for some of their data.
228 // 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 -0700229 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
230 {
231 delete mImageArray[i];
232 }
Austin Kinross69822602014-08-12 15:51:37 -0700233
234 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700235}
236
Brandon Jonescef06ff2014-08-05 13:27:48 -0700237Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238{
239 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700240 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700241 return mImageArray[level];
242}
243
Jamie Madillfeda4d22014-09-17 13:03:29 -0400244Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
245{
246 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
247 ASSERT(index.layerIndex == 0);
248 ASSERT(index.type == GL_TEXTURE_2D);
249 return mImageArray[index.mipIndex];
250}
251
Brandon Jonescef06ff2014-08-05 13:27:48 -0700252GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700253{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700254 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
255 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700256}
257
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258GLsizei TextureD3D_2D::getWidth(GLint level) const
259{
260 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
261 return mImageArray[level]->getWidth();
262 else
263 return 0;
264}
265
266GLsizei TextureD3D_2D::getHeight(GLint level) const
267{
268 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
269 return mImageArray[level]->getHeight();
270 else
271 return 0;
272}
273
274GLenum TextureD3D_2D::getInternalFormat(GLint level) const
275{
276 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
277 return mImageArray[level]->getInternalFormat();
278 else
279 return GL_NONE;
280}
281
282GLenum TextureD3D_2D::getActualFormat(GLint level) const
283{
284 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
285 return mImageArray[level]->getActualFormat();
286 else
287 return GL_NONE;
288}
289
290bool TextureD3D_2D::isDepth(GLint level) const
291{
Geoff Lang5d601382014-07-22 15:14:06 -0400292 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700293}
294
Brandon Jonescef06ff2014-08-05 13:27:48 -0700295void 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 -0700296{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700297 ASSERT(target == GL_TEXTURE_2D && depth == 1);
298
Geoff Lang5d601382014-07-22 15:14:06 -0400299 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
300
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700301 bool fastUnpacked = false;
302
Brandon Jonescef06ff2014-08-05 13:27:48 -0700303 redefineImage(level, sizedInternalFormat, width, height);
304
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700305 // Attempt a fast gpu copy of the pixel data to the surface
306 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
307 {
308 // Will try to create RT storage if it does not exist
Brandon Jonescef06ff2014-08-05 13:27:48 -0700309 RenderTarget *destRenderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700310 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
311
312 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
313 {
314 // Ensure we don't overwrite our newly initialized data
315 mImageArray[level]->markClean();
316
317 fastUnpacked = true;
318 }
319 }
320
321 if (!fastUnpacked)
322 {
323 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
324 }
325}
326
Brandon Jonescef06ff2014-08-05 13:27:48 -0700327void 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 -0700328{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700329 ASSERT(target == GL_TEXTURE_2D && depth == 1);
330
331 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
332 redefineImage(level, format, width, height);
333
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700334 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
335}
336
Brandon Jonescef06ff2014-08-05 13:27:48 -0700337void 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 -0700338{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700339 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
340
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700341 bool fastUnpacked = false;
342
343 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
344 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700345 RenderTarget *renderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700346 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
347
348 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
349 {
350 // Ensure we don't overwrite our newly initialized data
351 mImageArray[level]->markClean();
352
353 fastUnpacked = true;
354 }
355 }
356
Jamie Madillfeda4d22014-09-17 13:03:29 -0400357 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
358 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700359 {
360 commitRect(level, xoffset, yoffset, width, height);
361 }
362}
363
Brandon Jonescef06ff2014-08-05 13:27:48 -0700364void 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 -0700365{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700366 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
367
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700368 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
369 {
370 commitRect(level, xoffset, yoffset, width, height);
371 }
372}
373
Brandon Jonescef06ff2014-08-05 13:27:48 -0700374void 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 -0700375{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700376 ASSERT(target == GL_TEXTURE_2D);
377
378 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
379 redefineImage(level, sizedInternalFormat, width, height);
380
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700381 if (!mImageArray[level]->isRenderableFormat())
382 {
383 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
384 mDirtyImages = true;
385 }
386 else
387 {
388 ensureRenderTarget();
389 mImageArray[level]->markClean();
390
391 if (width != 0 && height != 0 && isValidLevel(level))
392 {
393 gl::Rectangle sourceRect;
394 sourceRect.x = x;
395 sourceRect.width = width;
396 sourceRect.y = y;
397 sourceRect.height = height;
398
399 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
400 }
401 }
402}
403
404void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
405{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700406 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
407
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700408 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
409 // the current level we're copying to is defined (with appropriate format, width & height)
410 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
411
412 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
413 {
414 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
415 mDirtyImages = true;
416 }
417 else
418 {
419 ensureRenderTarget();
420
421 if (isValidLevel(level))
422 {
423 updateStorageLevel(level);
424
425 gl::Rectangle sourceRect;
426 sourceRect.x = x;
427 sourceRect.width = width;
428 sourceRect.y = y;
429 sourceRect.height = height;
430
431 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400432 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700433 xoffset, yoffset, mTexStorage, level);
434 }
435 }
436}
437
Brandon Jonescef06ff2014-08-05 13:27:48 -0700438void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700439{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700440 ASSERT(target == GL_TEXTURE_2D && depth == 1);
441
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442 for (int level = 0; level < levels; level++)
443 {
444 GLsizei levelWidth = std::max(1, width >> level);
445 GLsizei levelHeight = std::max(1, height >> level);
446 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
447 }
448
449 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
450 {
451 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
452 }
453
454 mImmutable = true;
455
Brandon Jones78b1acd2014-07-15 15:33:07 -0700456 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700457}
458
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700459void TextureD3D_2D::bindTexImage(egl::Surface *surface)
460{
461 GLenum internalformat = surface->getFormat();
462
463 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
464
465 if (mTexStorage)
466 {
467 SafeDelete(mTexStorage);
468 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700469 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700470
471 mDirtyImages = true;
472}
473
474void TextureD3D_2D::releaseTexImage()
475{
476 if (mTexStorage)
477 {
478 SafeDelete(mTexStorage);
479 }
480
481 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
482 {
483 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
484 }
485}
486
487void TextureD3D_2D::generateMipmaps()
488{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700489 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700490 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700491 for (int level = 1; level < levelCount; level++)
492 {
493 redefineImage(level, getBaseLevelInternalFormat(),
494 std::max(getBaseLevelWidth() >> level, 1),
495 std::max(getBaseLevelHeight() >> level, 1));
496 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700497
498 if (mTexStorage && mTexStorage->isRenderTarget())
499 {
500 for (int level = 1; level < levelCount; level++)
501 {
502 mTexStorage->generateMipmap(level);
503
504 mImageArray[level]->markClean();
505 }
506 }
507 else
508 {
509 for (int level = 1; level < levelCount; level++)
510 {
511 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
512 }
513 }
514}
515
Brandon Jonescef06ff2014-08-05 13:27:48 -0700516unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700517{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700518 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
520}
521
Brandon Jonescef06ff2014-08-05 13:27:48 -0700522RenderTarget *TextureD3D_2D::getRenderTarget(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700523{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700524 ASSERT(layer == 0);
525
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700526 // ensure the underlying texture is created
527 if (!ensureRenderTarget())
528 {
529 return NULL;
530 }
531
532 updateStorageLevel(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700533 return mTexStorage->getRenderTarget(level);
534}
535
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536bool TextureD3D_2D::isValidLevel(int level) const
537{
538 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
539}
540
541bool TextureD3D_2D::isLevelComplete(int level) const
542{
543 if (isImmutable())
544 {
545 return true;
546 }
547
Brandon Jones78b1acd2014-07-15 15:33:07 -0700548 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700549
550 GLsizei width = baseImage->getWidth();
551 GLsizei height = baseImage->getHeight();
552
553 if (width <= 0 || height <= 0)
554 {
555 return false;
556 }
557
558 // The base image level is complete if the width and height are positive
559 if (level == 0)
560 {
561 return true;
562 }
563
564 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700565 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700566
567 if (image->getInternalFormat() != baseImage->getInternalFormat())
568 {
569 return false;
570 }
571
572 if (image->getWidth() != std::max(1, width >> level))
573 {
574 return false;
575 }
576
577 if (image->getHeight() != std::max(1, height >> level))
578 {
579 return false;
580 }
581
582 return true;
583}
584
585// Constructs a native texture resource from the texture images
586void TextureD3D_2D::initializeStorage(bool renderTarget)
587{
588 // Only initialize the first time this texture is used as a render target or shader resource
589 if (mTexStorage)
590 {
591 return;
592 }
593
594 // do not attempt to create storage for nonexistant data
595 if (!isLevelComplete(0))
596 {
597 return;
598 }
599
600 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
601
602 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
603 ASSERT(mTexStorage);
604
605 // flush image data to the storage
606 updateStorage();
607}
608
Brandon Jones78b1acd2014-07-15 15:33:07 -0700609TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610{
611 GLsizei width = getBaseLevelWidth();
612 GLsizei height = getBaseLevelHeight();
613
614 ASSERT(width > 0 && height > 0);
615
616 // use existing storage level count, when previously specified by TexStorage*D
617 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
618
Brandon Jones78b1acd2014-07-15 15:33:07 -0700619 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700620}
621
622void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
623{
624 SafeDelete(mTexStorage);
625 mTexStorage = newCompleteTexStorage;
626
627 if (mTexStorage && mTexStorage->isManaged())
628 {
629 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
630 {
631 mImageArray[level]->setManagedSurface(mTexStorage, level);
632 }
633 }
634
635 mDirtyImages = true;
636}
637
638void TextureD3D_2D::updateStorage()
639{
640 ASSERT(mTexStorage != NULL);
641 GLint storageLevels = mTexStorage->getLevelCount();
642 for (int level = 0; level < storageLevels; level++)
643 {
644 if (mImageArray[level]->isDirty() && isLevelComplete(level))
645 {
646 updateStorageLevel(level);
647 }
648 }
649}
650
651bool TextureD3D_2D::ensureRenderTarget()
652{
653 initializeStorage(true);
654
655 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
656 {
657 ASSERT(mTexStorage);
658 if (!mTexStorage->isRenderTarget())
659 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700660 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700661
662 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
663 {
664 delete newRenderTargetStorage;
665 return gl::error(GL_OUT_OF_MEMORY, false);
666 }
667
668 setCompleteTexStorage(newRenderTargetStorage);
669 }
670 }
671
672 return (mTexStorage && mTexStorage->isRenderTarget());
673}
674
675TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
676{
677 return mTexStorage;
678}
679
680const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
681{
682 return mImageArray[0];
683}
684
685void TextureD3D_2D::updateStorageLevel(int level)
686{
687 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
688 ASSERT(isLevelComplete(level));
689
690 if (mImageArray[level]->isDirty())
691 {
692 commitRect(level, 0, 0, getWidth(level), getHeight(level));
693 }
694}
695
696void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
697{
698 // If there currently is a corresponding storage texture image, it has these parameters
699 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
700 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
701 const GLenum storageFormat = getBaseLevelInternalFormat();
702
703 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
704
705 if (mTexStorage)
706 {
707 const int storageLevels = mTexStorage->getLevelCount();
708
709 if ((level >= storageLevels && storageLevels != 0) ||
710 width != storageWidth ||
711 height != storageHeight ||
712 internalformat != storageFormat) // Discard mismatched storage
713 {
714 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
715 {
716 mImageArray[i]->markDirty();
717 }
718
719 SafeDelete(mTexStorage);
720 mDirtyImages = true;
721 }
722 }
723}
724
725void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
726{
727 if (isValidLevel(level))
728 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700729 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700730 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
731 {
732 image->markClean();
733 }
734 }
735}
736
Brandon Jones0511e802014-07-14 16:27:26 -0700737
Brandon Jones78b1acd2014-07-15 15:33:07 -0700738TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700739 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700740 mTexStorage(NULL)
741{
742 for (int i = 0; i < 6; i++)
743 {
744 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
745 {
746 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
747 }
748 }
749}
750
751TextureD3D_Cube::~TextureD3D_Cube()
752{
Austin Kinross69822602014-08-12 15:51:37 -0700753 // Delete the Images before the TextureStorage.
754 // Images might be relying on the TextureStorage for some of their data.
755 // 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 -0700756 for (int i = 0; i < 6; i++)
757 {
758 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
759 {
760 SafeDelete(mImageArray[i][j]);
761 }
762 }
Austin Kinross69822602014-08-12 15:51:37 -0700763
764 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700765}
766
Brandon Jonescef06ff2014-08-05 13:27:48 -0700767Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700768{
769 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700770 ASSERT(layer < 6);
771 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700772}
773
Jamie Madillfeda4d22014-09-17 13:03:29 -0400774Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
775{
776 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
777 ASSERT(index.layerIndex < 6);
778 return mImageArray[index.layerIndex][index.mipIndex];
779}
780
Brandon Jonescef06ff2014-08-05 13:27:48 -0700781GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700782{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700783 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
784 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700785}
786
Brandon Jonescef06ff2014-08-05 13:27:48 -0700787GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700788{
789 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700790 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700791 else
792 return GL_NONE;
793}
794
Brandon Jonescef06ff2014-08-05 13:27:48 -0700795bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700796{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700797 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700798}
799
Brandon Jonescef06ff2014-08-05 13:27:48 -0700800void 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 -0700801{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802 ASSERT(depth == 1);
803
804 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400805 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700806
807 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
808
809 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
810}
811
Brandon Jonescef06ff2014-08-05 13:27:48 -0700812void 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 -0700813{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700814 ASSERT(depth == 1);
815
Brandon Jones0511e802014-07-14 16:27:26 -0700816 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
818
Brandon Jones0511e802014-07-14 16:27:26 -0700819 redefineImage(faceIndex, level, format, width, height);
820
821 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
822}
823
Brandon Jonescef06ff2014-08-05 13:27:48 -0700824void 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 -0700825{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700826 ASSERT(depth == 1 && zoffset == 0);
827
828 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
829
Jamie Madillfeda4d22014-09-17 13:03:29 -0400830 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
831 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700832 {
833 commitRect(faceIndex, level, xoffset, yoffset, width, height);
834 }
835}
836
Brandon Jonescef06ff2014-08-05 13:27:48 -0700837void 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 -0700838{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700839 ASSERT(depth == 1 && zoffset == 0);
840
841 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
842
Brandon Jones0511e802014-07-14 16:27:26 -0700843 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
844 {
845 commitRect(faceIndex, level, xoffset, yoffset, width, height);
846 }
847}
848
849void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
850{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700851 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400852 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
853
Brandon Jones0511e802014-07-14 16:27:26 -0700854 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
855
856 if (!mImageArray[faceIndex][level]->isRenderableFormat())
857 {
858 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
859 mDirtyImages = true;
860 }
861 else
862 {
863 ensureRenderTarget();
864 mImageArray[faceIndex][level]->markClean();
865
866 ASSERT(width == height);
867
868 if (width > 0 && isValidFaceLevel(faceIndex, level))
869 {
870 gl::Rectangle sourceRect;
871 sourceRect.x = x;
872 sourceRect.width = width;
873 sourceRect.y = y;
874 sourceRect.height = height;
875
876 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
877 }
878 }
879}
880
881void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
882{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700883 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700884
885 // We can only make our texture storage to a render target if the level we're copying *to* is complete
886 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
887 // rely on the "getBaseLevel*" methods reliably otherwise.
888 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
889
890 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
891 {
892 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
893 mDirtyImages = true;
894 }
895 else
896 {
897 ensureRenderTarget();
898
899 if (isValidFaceLevel(faceIndex, level))
900 {
901 updateStorageFaceLevel(faceIndex, level);
902
903 gl::Rectangle sourceRect;
904 sourceRect.x = x;
905 sourceRect.width = width;
906 sourceRect.y = y;
907 sourceRect.height = height;
908
Geoff Lang5d601382014-07-22 15:14:06 -0400909 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700910 xoffset, yoffset, mTexStorage, target, level);
911 }
912 }
913}
914
Brandon Jonescef06ff2014-08-05 13:27:48 -0700915void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700916{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700917 ASSERT(width == height);
918 ASSERT(depth == 1);
919
Brandon Jones0511e802014-07-14 16:27:26 -0700920 for (int level = 0; level < levels; level++)
921 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700922 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700923 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
924 {
925 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
926 }
927 }
928
929 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
930 {
931 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
932 {
933 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
934 }
935 }
936
937 mImmutable = true;
938
Brandon Jonescef06ff2014-08-05 13:27:48 -0700939 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700940}
941
Brandon Jones0511e802014-07-14 16:27:26 -0700942// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
943bool TextureD3D_Cube::isCubeComplete() const
944{
945 int baseWidth = getBaseLevelWidth();
946 int baseHeight = getBaseLevelHeight();
947 GLenum baseFormat = getBaseLevelInternalFormat();
948
949 if (baseWidth <= 0 || baseWidth != baseHeight)
950 {
951 return false;
952 }
953
954 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
955 {
956 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
957
958 if (faceBaseImage.getWidth() != baseWidth ||
959 faceBaseImage.getHeight() != baseHeight ||
960 faceBaseImage.getInternalFormat() != baseFormat )
961 {
962 return false;
963 }
964 }
965
966 return true;
967}
968
Brandon Jones6053a522014-07-25 16:22:09 -0700969void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
970{
971 UNREACHABLE();
972}
973
974void TextureD3D_Cube::releaseTexImage()
975{
976 UNREACHABLE();
977}
978
979
Brandon Jones0511e802014-07-14 16:27:26 -0700980void TextureD3D_Cube::generateMipmaps()
981{
982 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
983 int levelCount = mipLevels();
984 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
985 {
986 for (int level = 1; level < levelCount; level++)
987 {
988 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
989 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
990 }
991 }
992
993 if (mTexStorage && mTexStorage->isRenderTarget())
994 {
995 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
996 {
997 for (int level = 1; level < levelCount; level++)
998 {
999 mTexStorage->generateMipmap(faceIndex, level);
1000
1001 mImageArray[faceIndex][level]->markClean();
1002 }
1003 }
1004 }
1005 else
1006 {
1007 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1008 {
1009 for (int level = 1; level < levelCount; level++)
1010 {
1011 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1012 }
1013 }
1014 }
1015}
1016
Brandon Jonescef06ff2014-08-05 13:27:48 -07001017unsigned int TextureD3D_Cube::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001018{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001019 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001020 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1021}
1022
Brandon Jonescef06ff2014-08-05 13:27:48 -07001023RenderTarget *TextureD3D_Cube::getRenderTarget(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001024{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001025 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001026 ASSERT(gl::IsCubemapTextureTarget(target));
1027
1028 // ensure the underlying texture is created
1029 if (!ensureRenderTarget())
1030 {
1031 return NULL;
1032 }
1033
Brandon Jonescef06ff2014-08-05 13:27:48 -07001034 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001035 return mTexStorage->getRenderTarget(target, level);
1036}
1037
Brandon Jones0511e802014-07-14 16:27:26 -07001038void TextureD3D_Cube::initializeStorage(bool renderTarget)
1039{
1040 // Only initialize the first time this texture is used as a render target or shader resource
1041 if (mTexStorage)
1042 {
1043 return;
1044 }
1045
1046 // do not attempt to create storage for nonexistant data
1047 if (!isFaceLevelComplete(0, 0))
1048 {
1049 return;
1050 }
1051
1052 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1053
1054 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1055 ASSERT(mTexStorage);
1056
1057 // flush image data to the storage
1058 updateStorage();
1059}
1060
1061TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1062{
1063 GLsizei size = getBaseLevelWidth();
1064
1065 ASSERT(size > 0);
1066
1067 // use existing storage level count, when previously specified by TexStorage*D
1068 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1069
1070 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1071}
1072
1073void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1074{
1075 SafeDelete(mTexStorage);
1076 mTexStorage = newCompleteTexStorage;
1077
1078 if (mTexStorage && mTexStorage->isManaged())
1079 {
1080 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1081 {
1082 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1083 {
1084 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1085 }
1086 }
1087 }
1088
1089 mDirtyImages = true;
1090}
1091
1092void TextureD3D_Cube::updateStorage()
1093{
1094 ASSERT(mTexStorage != NULL);
1095 GLint storageLevels = mTexStorage->getLevelCount();
1096 for (int face = 0; face < 6; face++)
1097 {
1098 for (int level = 0; level < storageLevels; level++)
1099 {
1100 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1101 {
1102 updateStorageFaceLevel(face, level);
1103 }
1104 }
1105 }
1106}
1107
1108bool TextureD3D_Cube::ensureRenderTarget()
1109{
1110 initializeStorage(true);
1111
1112 if (getBaseLevelWidth() > 0)
1113 {
1114 ASSERT(mTexStorage);
1115 if (!mTexStorage->isRenderTarget())
1116 {
1117 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1118
1119 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1120 {
1121 delete newRenderTargetStorage;
1122 return gl::error(GL_OUT_OF_MEMORY, false);
1123 }
1124
1125 setCompleteTexStorage(newRenderTargetStorage);
1126 }
1127 }
1128
1129 return (mTexStorage && mTexStorage->isRenderTarget());
1130}
1131
1132TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1133{
1134 return mTexStorage;
1135}
1136
1137const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1138{
1139 // Note: if we are not cube-complete, there is no single base level image that can describe all
1140 // cube faces, so this method is only well-defined for a cube-complete base level.
1141 return mImageArray[0][0];
1142}
1143
Brandon Jones0511e802014-07-14 16:27:26 -07001144bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1145{
1146 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1147}
1148
Brandon Jones0511e802014-07-14 16:27:26 -07001149bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1150{
1151 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1152
1153 if (isImmutable())
1154 {
1155 return true;
1156 }
1157
1158 int baseSize = getBaseLevelWidth();
1159
1160 if (baseSize <= 0)
1161 {
1162 return false;
1163 }
1164
1165 // "isCubeComplete" checks for base level completeness and we must call that
1166 // to determine if any face at level 0 is complete. We omit that check here
1167 // to avoid re-checking cube-completeness for every face at level 0.
1168 if (level == 0)
1169 {
1170 return true;
1171 }
1172
1173 // Check that non-zero levels are consistent with the base level.
1174 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1175
1176 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1177 {
1178 return false;
1179 }
1180
1181 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1182 {
1183 return false;
1184 }
1185
1186 return true;
1187}
1188
1189void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1190{
1191 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1192 ImageD3D *image = mImageArray[faceIndex][level];
1193
1194 if (image->isDirty())
1195 {
1196 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1197 }
1198}
1199
1200void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1201{
1202 // If there currently is a corresponding storage texture image, it has these parameters
1203 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1204 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1205 const GLenum storageFormat = getBaseLevelInternalFormat();
1206
1207 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1208
1209 if (mTexStorage)
1210 {
1211 const int storageLevels = mTexStorage->getLevelCount();
1212
1213 if ((level >= storageLevels && storageLevels != 0) ||
1214 width != storageWidth ||
1215 height != storageHeight ||
1216 internalformat != storageFormat) // Discard mismatched storage
1217 {
1218 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1219 {
1220 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1221 {
1222 mImageArray[faceIndex][level]->markDirty();
1223 }
1224 }
1225
1226 SafeDelete(mTexStorage);
1227
1228 mDirtyImages = true;
1229 }
1230 }
1231}
1232
1233void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1234{
1235 if (isValidFaceLevel(faceIndex, level))
1236 {
1237 ImageD3D *image = mImageArray[faceIndex][level];
1238 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1239 image->markClean();
1240 }
1241}
1242
Brandon Jones78b1acd2014-07-15 15:33:07 -07001243
1244TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001245 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001246 mTexStorage(NULL)
1247{
1248 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1249 {
1250 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1251 }
1252}
1253
1254TextureD3D_3D::~TextureD3D_3D()
1255{
Austin Kinross69822602014-08-12 15:51:37 -07001256 // Delete the Images before the TextureStorage.
1257 // Images might be relying on the TextureStorage for some of their data.
1258 // 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 -07001259 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1260 {
1261 delete mImageArray[i];
1262 }
Austin Kinross69822602014-08-12 15:51:37 -07001263
1264 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001265}
1266
Brandon Jonescef06ff2014-08-05 13:27:48 -07001267Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001268{
1269 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001270 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001271 return mImageArray[level];
1272}
1273
Jamie Madillfeda4d22014-09-17 13:03:29 -04001274Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1275{
1276 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1277 ASSERT(index.layerIndex == 0);
1278 ASSERT(index.type == GL_TEXTURE_3D);
1279 return mImageArray[index.mipIndex];
1280}
1281
Brandon Jonescef06ff2014-08-05 13:27:48 -07001282GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001283{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001284 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1285 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001286}
1287
Brandon Jones78b1acd2014-07-15 15:33:07 -07001288GLsizei TextureD3D_3D::getWidth(GLint level) const
1289{
1290 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1291 return mImageArray[level]->getWidth();
1292 else
1293 return 0;
1294}
1295
1296GLsizei TextureD3D_3D::getHeight(GLint level) const
1297{
1298 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1299 return mImageArray[level]->getHeight();
1300 else
1301 return 0;
1302}
1303
1304GLsizei TextureD3D_3D::getDepth(GLint level) const
1305{
1306 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1307 return mImageArray[level]->getDepth();
1308 else
1309 return 0;
1310}
1311
1312GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1313{
1314 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1315 return mImageArray[level]->getInternalFormat();
1316 else
1317 return GL_NONE;
1318}
1319
1320bool TextureD3D_3D::isDepth(GLint level) const
1321{
Geoff Lang5d601382014-07-22 15:14:06 -04001322 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001323}
1324
Brandon Jonescef06ff2014-08-05 13:27:48 -07001325void 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 -07001326{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001327 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001328 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1329
Brandon Jones78b1acd2014-07-15 15:33:07 -07001330 redefineImage(level, sizedInternalFormat, width, height, depth);
1331
1332 bool fastUnpacked = false;
1333
1334 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1335 if (isFastUnpackable(unpack, sizedInternalFormat))
1336 {
1337 // Will try to create RT storage if it does not exist
1338 RenderTarget *destRenderTarget = getRenderTarget(level);
1339 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1340
1341 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1342 {
1343 // Ensure we don't overwrite our newly initialized data
1344 mImageArray[level]->markClean();
1345
1346 fastUnpacked = true;
1347 }
1348 }
1349
1350 if (!fastUnpacked)
1351 {
1352 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1353 }
1354}
1355
Brandon Jonescef06ff2014-08-05 13:27:48 -07001356void 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 -07001357{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001358 ASSERT(target == GL_TEXTURE_3D);
1359
Brandon Jones78b1acd2014-07-15 15:33:07 -07001360 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1361 redefineImage(level, format, width, height, depth);
1362
1363 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1364}
1365
Brandon Jonescef06ff2014-08-05 13:27:48 -07001366void 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 -07001367{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001368 ASSERT(target == GL_TEXTURE_3D);
1369
Brandon Jones78b1acd2014-07-15 15:33:07 -07001370 bool fastUnpacked = false;
1371
1372 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1373 if (isFastUnpackable(unpack, getInternalFormat(level)))
1374 {
1375 RenderTarget *destRenderTarget = getRenderTarget(level);
1376 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1377
1378 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1379 {
1380 // Ensure we don't overwrite our newly initialized data
1381 mImageArray[level]->markClean();
1382
1383 fastUnpacked = true;
1384 }
1385 }
1386
Jamie Madillfeda4d22014-09-17 13:03:29 -04001387 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1388 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001389 {
1390 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1391 }
1392}
1393
Brandon Jonescef06ff2014-08-05 13:27:48 -07001394void 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 -07001395{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001396 ASSERT(target == GL_TEXTURE_3D);
1397
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1399 {
1400 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1401 }
1402}
1403
Brandon Jonescef06ff2014-08-05 13:27:48 -07001404void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1405{
1406 UNIMPLEMENTED();
1407}
1408
Brandon Jones78b1acd2014-07-15 15:33:07 -07001409void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1410{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001411 ASSERT(target == GL_TEXTURE_3D);
1412
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1414 // the current level we're copying to is defined (with appropriate format, width & height)
1415 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1416
1417 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1418 {
1419 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1420 mDirtyImages = true;
1421 }
1422 else
1423 {
1424 ensureRenderTarget();
1425
1426 if (isValidLevel(level))
1427 {
1428 updateStorageLevel(level);
1429
1430 gl::Rectangle sourceRect;
1431 sourceRect.x = x;
1432 sourceRect.width = width;
1433 sourceRect.y = y;
1434 sourceRect.height = height;
1435
1436 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001437 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001438 xoffset, yoffset, zoffset, mTexStorage, level);
1439 }
1440 }
1441}
1442
Brandon Jonescef06ff2014-08-05 13:27:48 -07001443void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001444{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001445 ASSERT(target == GL_TEXTURE_3D);
1446
Brandon Jones78b1acd2014-07-15 15:33:07 -07001447 for (int level = 0; level < levels; level++)
1448 {
1449 GLsizei levelWidth = std::max(1, width >> level);
1450 GLsizei levelHeight = std::max(1, height >> level);
1451 GLsizei levelDepth = std::max(1, depth >> level);
1452 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1453 }
1454
1455 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1456 {
1457 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1458 }
1459
1460 mImmutable = true;
1461
1462 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1463}
1464
Brandon Jones6053a522014-07-25 16:22:09 -07001465void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001466{
Brandon Jones6053a522014-07-25 16:22:09 -07001467 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001468}
1469
Brandon Jones6053a522014-07-25 16:22:09 -07001470void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471{
Brandon Jones6053a522014-07-25 16:22:09 -07001472 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001473}
1474
Brandon Jones6053a522014-07-25 16:22:09 -07001475
Brandon Jones78b1acd2014-07-15 15:33:07 -07001476void TextureD3D_3D::generateMipmaps()
1477{
1478 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1479 int levelCount = mipLevels();
1480 for (int level = 1; level < levelCount; level++)
1481 {
1482 redefineImage(level, getBaseLevelInternalFormat(),
1483 std::max(getBaseLevelWidth() >> level, 1),
1484 std::max(getBaseLevelHeight() >> level, 1),
1485 std::max(getBaseLevelDepth() >> level, 1));
1486 }
1487
1488 if (mTexStorage && mTexStorage->isRenderTarget())
1489 {
1490 for (int level = 1; level < levelCount; level++)
1491 {
1492 mTexStorage->generateMipmap(level);
1493
1494 mImageArray[level]->markClean();
1495 }
1496 }
1497 else
1498 {
1499 for (int level = 1; level < levelCount; level++)
1500 {
1501 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1502 }
1503 }
1504}
1505
1506unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1507{
1508 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1509}
1510
1511RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1512{
1513 // ensure the underlying texture is created
1514 if (!ensureRenderTarget())
1515 {
1516 return NULL;
1517 }
1518
1519 updateStorageLevel(level);
1520
1521 // ensure this is NOT a depth texture
1522 if (isDepth(level))
1523 {
1524 return NULL;
1525 }
1526
1527 return mTexStorage->getRenderTarget(level);
1528}
1529
1530RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1531{
1532 // ensure the underlying texture is created
1533 if (!ensureRenderTarget())
1534 {
1535 return NULL;
1536 }
1537
1538 updateStorage();
1539
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540 return mTexStorage->getRenderTarget(level, layer);
1541}
1542
1543void TextureD3D_3D::initializeStorage(bool renderTarget)
1544{
1545 // Only initialize the first time this texture is used as a render target or shader resource
1546 if (mTexStorage)
1547 {
1548 return;
1549 }
1550
1551 // do not attempt to create storage for nonexistant data
1552 if (!isLevelComplete(0))
1553 {
1554 return;
1555 }
1556
1557 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1558
1559 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1560 ASSERT(mTexStorage);
1561
1562 // flush image data to the storage
1563 updateStorage();
1564}
1565
1566TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1567{
1568 GLsizei width = getBaseLevelWidth();
1569 GLsizei height = getBaseLevelHeight();
1570 GLsizei depth = getBaseLevelDepth();
1571
1572 ASSERT(width > 0 && height > 0 && depth > 0);
1573
1574 // use existing storage level count, when previously specified by TexStorage*D
1575 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1576
1577 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1578}
1579
1580void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1581{
1582 SafeDelete(mTexStorage);
1583 mTexStorage = newCompleteTexStorage;
1584 mDirtyImages = true;
1585
1586 // We do not support managed 3D storage, as that is D3D9/ES2-only
1587 ASSERT(!mTexStorage->isManaged());
1588}
1589
1590void TextureD3D_3D::updateStorage()
1591{
1592 ASSERT(mTexStorage != NULL);
1593 GLint storageLevels = mTexStorage->getLevelCount();
1594 for (int level = 0; level < storageLevels; level++)
1595 {
1596 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1597 {
1598 updateStorageLevel(level);
1599 }
1600 }
1601}
1602
1603bool TextureD3D_3D::ensureRenderTarget()
1604{
1605 initializeStorage(true);
1606
1607 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1608 {
1609 ASSERT(mTexStorage);
1610 if (!mTexStorage->isRenderTarget())
1611 {
1612 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1613
1614 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1615 {
1616 delete newRenderTargetStorage;
1617 return gl::error(GL_OUT_OF_MEMORY, false);
1618 }
1619
1620 setCompleteTexStorage(newRenderTargetStorage);
1621 }
1622 }
1623
1624 return (mTexStorage && mTexStorage->isRenderTarget());
1625}
1626
1627TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1628{
1629 return mTexStorage;
1630}
1631
1632const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1633{
1634 return mImageArray[0];
1635}
1636
1637bool TextureD3D_3D::isValidLevel(int level) const
1638{
1639 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1640}
1641
1642bool TextureD3D_3D::isLevelComplete(int level) const
1643{
1644 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1645
1646 if (isImmutable())
1647 {
1648 return true;
1649 }
1650
1651 GLsizei width = getBaseLevelWidth();
1652 GLsizei height = getBaseLevelHeight();
1653 GLsizei depth = getBaseLevelDepth();
1654
1655 if (width <= 0 || height <= 0 || depth <= 0)
1656 {
1657 return false;
1658 }
1659
1660 if (level == 0)
1661 {
1662 return true;
1663 }
1664
1665 ImageD3D *levelImage = mImageArray[level];
1666
1667 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1668 {
1669 return false;
1670 }
1671
1672 if (levelImage->getWidth() != std::max(1, width >> level))
1673 {
1674 return false;
1675 }
1676
1677 if (levelImage->getHeight() != std::max(1, height >> level))
1678 {
1679 return false;
1680 }
1681
1682 if (levelImage->getDepth() != std::max(1, depth >> level))
1683 {
1684 return false;
1685 }
1686
1687 return true;
1688}
1689
1690void TextureD3D_3D::updateStorageLevel(int level)
1691{
1692 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1693 ASSERT(isLevelComplete(level));
1694
1695 if (mImageArray[level]->isDirty())
1696 {
1697 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1698 }
1699}
1700
1701void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1702{
1703 // If there currently is a corresponding storage texture image, it has these parameters
1704 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1705 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1706 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1707 const GLenum storageFormat = getBaseLevelInternalFormat();
1708
1709 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1710
1711 if (mTexStorage)
1712 {
1713 const int storageLevels = mTexStorage->getLevelCount();
1714
1715 if ((level >= storageLevels && storageLevels != 0) ||
1716 width != storageWidth ||
1717 height != storageHeight ||
1718 depth != storageDepth ||
1719 internalformat != storageFormat) // Discard mismatched storage
1720 {
1721 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1722 {
1723 mImageArray[i]->markDirty();
1724 }
1725
1726 SafeDelete(mTexStorage);
1727 mDirtyImages = true;
1728 }
1729 }
1730}
1731
1732void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1733{
1734 if (isValidLevel(level))
1735 {
1736 ImageD3D *image = mImageArray[level];
1737 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1738 {
1739 image->markClean();
1740 }
1741 }
1742}
1743
Brandon Jones142ec422014-07-16 10:31:30 -07001744
1745TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001746 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001747 mTexStorage(NULL)
1748{
1749 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1750 {
1751 mLayerCounts[level] = 0;
1752 mImageArray[level] = NULL;
1753 }
1754}
1755
1756TextureD3D_2DArray::~TextureD3D_2DArray()
1757{
Austin Kinross69822602014-08-12 15:51:37 -07001758 // Delete the Images before the TextureStorage.
1759 // Images might be relying on the TextureStorage for some of their data.
1760 // 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 -07001761 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001762 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001763}
1764
Brandon Jones142ec422014-07-16 10:31:30 -07001765Image *TextureD3D_2DArray::getImage(int level, int layer) const
1766{
1767 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1768 ASSERT(layer < mLayerCounts[level]);
1769 return mImageArray[level][layer];
1770}
1771
Jamie Madillfeda4d22014-09-17 13:03:29 -04001772Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1773{
1774 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1775 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1776 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1777 return mImageArray[index.mipIndex][index.layerIndex];
1778}
1779
Brandon Jones142ec422014-07-16 10:31:30 -07001780GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1781{
1782 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1783 return mLayerCounts[level];
1784}
1785
Brandon Jones142ec422014-07-16 10:31:30 -07001786GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1787{
1788 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1789}
1790
1791GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1792{
1793 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1794}
1795
1796GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1797{
1798 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1799}
1800
1801GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1802{
1803 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1804}
1805
1806bool TextureD3D_2DArray::isDepth(GLint level) const
1807{
Geoff Lang5d601382014-07-22 15:14:06 -04001808 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001809}
1810
Brandon Jonescef06ff2014-08-05 13:27:48 -07001811void 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 -07001812{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001813 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1814
Geoff Lang5d601382014-07-22 15:14:06 -04001815 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1816
Brandon Jones142ec422014-07-16 10:31:30 -07001817 redefineImage(level, sizedInternalFormat, width, height, depth);
1818
Geoff Lang5d601382014-07-22 15:14:06 -04001819 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1820 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001821
1822 for (int i = 0; i < depth; i++)
1823 {
1824 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1825 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1826 }
1827}
1828
Brandon Jonescef06ff2014-08-05 13:27:48 -07001829void 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 -07001830{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001831 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1832
Brandon Jones142ec422014-07-16 10:31:30 -07001833 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1834 redefineImage(level, format, width, height, depth);
1835
Geoff Lang5d601382014-07-22 15:14:06 -04001836 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1837 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001838
1839 for (int i = 0; i < depth; i++)
1840 {
1841 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1842 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1843 }
1844}
1845
Brandon Jonescef06ff2014-08-05 13:27:48 -07001846void 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 -07001847{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001848 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1849
Geoff Lang5d601382014-07-22 15:14:06 -04001850 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1851 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001852
1853 for (int i = 0; i < depth; i++)
1854 {
1855 int layer = zoffset + i;
1856 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1857
Jamie Madillfeda4d22014-09-17 13:03:29 -04001858 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1859 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001860 {
1861 commitRect(level, xoffset, yoffset, layer, width, height);
1862 }
1863 }
1864}
1865
Brandon Jonescef06ff2014-08-05 13:27:48 -07001866void 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 -07001867{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001868 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1869
Geoff Lang5d601382014-07-22 15:14:06 -04001870 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1871 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001872
1873 for (int i = 0; i < depth; i++)
1874 {
1875 int layer = zoffset + i;
1876 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1877
1878 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1879 {
1880 commitRect(level, xoffset, yoffset, layer, width, height);
1881 }
1882 }
1883}
1884
Brandon Jonescef06ff2014-08-05 13:27:48 -07001885void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1886{
1887 UNIMPLEMENTED();
1888}
1889
Brandon Jones142ec422014-07-16 10:31:30 -07001890void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1891{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001892 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1893
Brandon Jones142ec422014-07-16 10:31:30 -07001894 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1895 // the current level we're copying to is defined (with appropriate format, width & height)
1896 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1897
1898 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1899 {
1900 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1901 mDirtyImages = true;
1902 }
1903 else
1904 {
1905 ensureRenderTarget();
1906
1907 if (isValidLevel(level))
1908 {
1909 updateStorageLevel(level);
1910
1911 gl::Rectangle sourceRect;
1912 sourceRect.x = x;
1913 sourceRect.width = width;
1914 sourceRect.y = y;
1915 sourceRect.height = height;
1916
Geoff Lang5d601382014-07-22 15:14:06 -04001917 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001918 xoffset, yoffset, zoffset, mTexStorage, level);
1919 }
1920 }
1921}
1922
Brandon Jonescef06ff2014-08-05 13:27:48 -07001923void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001924{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001925 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1926
Brandon Jones142ec422014-07-16 10:31:30 -07001927 deleteImages();
1928
1929 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1930 {
1931 GLsizei levelWidth = std::max(1, width >> level);
1932 GLsizei levelHeight = std::max(1, height >> level);
1933
1934 mLayerCounts[level] = (level < levels ? depth : 0);
1935
1936 if (mLayerCounts[level] > 0)
1937 {
1938 // Create new images for this level
1939 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1940
1941 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1942 {
1943 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1944 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1945 levelHeight, 1, true);
1946 }
1947 }
1948 }
1949
1950 mImmutable = true;
1951 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1952}
1953
Brandon Jones6053a522014-07-25 16:22:09 -07001954void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001955{
Brandon Jones6053a522014-07-25 16:22:09 -07001956 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001957}
1958
Brandon Jones6053a522014-07-25 16:22:09 -07001959void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001960{
Brandon Jones6053a522014-07-25 16:22:09 -07001961 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001962}
1963
Brandon Jones6053a522014-07-25 16:22:09 -07001964
Brandon Jones142ec422014-07-16 10:31:30 -07001965void TextureD3D_2DArray::generateMipmaps()
1966{
1967 int baseWidth = getBaseLevelWidth();
1968 int baseHeight = getBaseLevelHeight();
1969 int baseDepth = getBaseLevelDepth();
1970 GLenum baseFormat = getBaseLevelInternalFormat();
1971
1972 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1973 int levelCount = mipLevels();
1974 for (int level = 1; level < levelCount; level++)
1975 {
1976 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1977 }
1978
1979 if (mTexStorage && mTexStorage->isRenderTarget())
1980 {
1981 for (int level = 1; level < levelCount; level++)
1982 {
1983 mTexStorage->generateMipmap(level);
1984
1985 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1986 {
1987 mImageArray[level][layer]->markClean();
1988 }
1989 }
1990 }
1991 else
1992 {
1993 for (int level = 1; level < levelCount; level++)
1994 {
1995 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1996 {
1997 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
1998 }
1999 }
2000 }
2001}
2002
2003unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2004{
2005 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2006}
2007
2008RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2009{
2010 // ensure the underlying texture is created
2011 if (!ensureRenderTarget())
2012 {
2013 return NULL;
2014 }
2015
2016 updateStorageLevel(level);
Brandon Jones142ec422014-07-16 10:31:30 -07002017 return mTexStorage->getRenderTarget(level, layer);
2018}
2019
2020void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2021{
2022 // Only initialize the first time this texture is used as a render target or shader resource
2023 if (mTexStorage)
2024 {
2025 return;
2026 }
2027
2028 // do not attempt to create storage for nonexistant data
2029 if (!isLevelComplete(0))
2030 {
2031 return;
2032 }
2033
2034 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2035
2036 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2037 ASSERT(mTexStorage);
2038
2039 // flush image data to the storage
2040 updateStorage();
2041}
2042
2043TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2044{
2045 GLsizei width = getBaseLevelWidth();
2046 GLsizei height = getBaseLevelHeight();
2047 GLsizei depth = getLayers(0);
2048
2049 ASSERT(width > 0 && height > 0 && depth > 0);
2050
2051 // use existing storage level count, when previously specified by TexStorage*D
2052 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2053
2054 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2055}
2056
2057void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2058{
2059 SafeDelete(mTexStorage);
2060 mTexStorage = newCompleteTexStorage;
2061 mDirtyImages = true;
2062
2063 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2064 ASSERT(!mTexStorage->isManaged());
2065}
2066
2067void TextureD3D_2DArray::updateStorage()
2068{
2069 ASSERT(mTexStorage != NULL);
2070 GLint storageLevels = mTexStorage->getLevelCount();
2071 for (int level = 0; level < storageLevels; level++)
2072 {
2073 if (isLevelComplete(level))
2074 {
2075 updateStorageLevel(level);
2076 }
2077 }
2078}
2079
2080bool TextureD3D_2DArray::ensureRenderTarget()
2081{
2082 initializeStorage(true);
2083
2084 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2085 {
2086 ASSERT(mTexStorage);
2087 if (!mTexStorage->isRenderTarget())
2088 {
2089 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2090
2091 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2092 {
2093 delete newRenderTargetStorage;
2094 return gl::error(GL_OUT_OF_MEMORY, false);
2095 }
2096
2097 setCompleteTexStorage(newRenderTargetStorage);
2098 }
2099 }
2100
2101 return (mTexStorage && mTexStorage->isRenderTarget());
2102}
2103
2104const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2105{
2106 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2107}
2108
2109TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2110{
2111 return mTexStorage;
2112}
2113
2114bool TextureD3D_2DArray::isValidLevel(int level) const
2115{
2116 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2117}
2118
2119bool TextureD3D_2DArray::isLevelComplete(int level) const
2120{
2121 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2122
2123 if (isImmutable())
2124 {
2125 return true;
2126 }
2127
2128 GLsizei width = getBaseLevelWidth();
2129 GLsizei height = getBaseLevelHeight();
2130 GLsizei layers = getLayers(0);
2131
2132 if (width <= 0 || height <= 0 || layers <= 0)
2133 {
2134 return false;
2135 }
2136
2137 if (level == 0)
2138 {
2139 return true;
2140 }
2141
2142 if (getInternalFormat(level) != getInternalFormat(0))
2143 {
2144 return false;
2145 }
2146
2147 if (getWidth(level) != std::max(1, width >> level))
2148 {
2149 return false;
2150 }
2151
2152 if (getHeight(level) != std::max(1, height >> level))
2153 {
2154 return false;
2155 }
2156
2157 if (getLayers(level) != layers)
2158 {
2159 return false;
2160 }
2161
2162 return true;
2163}
2164
2165void TextureD3D_2DArray::updateStorageLevel(int level)
2166{
2167 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2168 ASSERT(isLevelComplete(level));
2169
2170 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2171 {
2172 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2173 if (mImageArray[level][layer]->isDirty())
2174 {
2175 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2176 }
2177 }
2178}
2179
2180void TextureD3D_2DArray::deleteImages()
2181{
2182 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2183 {
2184 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2185 {
2186 delete mImageArray[level][layer];
2187 }
2188 delete[] mImageArray[level];
2189 mImageArray[level] = NULL;
2190 mLayerCounts[level] = 0;
2191 }
2192}
2193
2194void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2195{
2196 // If there currently is a corresponding storage texture image, it has these parameters
2197 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2198 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2199 const int storageDepth = getLayers(0);
2200 const GLenum storageFormat = getBaseLevelInternalFormat();
2201
2202 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2203 {
2204 delete mImageArray[level][layer];
2205 }
2206 delete[] mImageArray[level];
2207 mImageArray[level] = NULL;
2208 mLayerCounts[level] = depth;
2209
2210 if (depth > 0)
2211 {
2212 mImageArray[level] = new ImageD3D*[depth]();
2213
2214 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2215 {
2216 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2217 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2218 }
2219 }
2220
2221 if (mTexStorage)
2222 {
2223 const int storageLevels = mTexStorage->getLevelCount();
2224
2225 if ((level >= storageLevels && storageLevels != 0) ||
2226 width != storageWidth ||
2227 height != storageHeight ||
2228 depth != storageDepth ||
2229 internalformat != storageFormat) // Discard mismatched storage
2230 {
2231 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2232 {
2233 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2234 {
2235 mImageArray[level][layer]->markDirty();
2236 }
2237 }
2238
2239 delete mTexStorage;
2240 mTexStorage = NULL;
2241 mDirtyImages = true;
2242 }
2243 }
2244}
2245
2246void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2247{
2248 if (isValidLevel(level) && layerTarget < getLayers(level))
2249 {
2250 ImageD3D *image = mImageArray[level][layerTarget];
2251 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2252 {
2253 image->markClean();
2254 }
2255 }
2256}
2257
Brandon Jones78b1acd2014-07-15 15:33:07 -07002258}