blob: e3f457ef10abea5103db5e6221109ada84138acb [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
Jamie Madillea247592014-08-28 10:37:08 -04009#include "libGLESv2/common_includes.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070010#include "common/mathutil.h"
Brandon Jones0511e802014-07-14 16:27:26 -070011#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libEGL/Surface.h"
13#include "libGLESv2/Buffer.h"
14#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070015#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070016#include "libGLESv2/main.h"
17#include "libGLESv2/formatutils.h"
18#include "libGLESv2/renderer/BufferImpl.h"
19#include "libGLESv2/renderer/RenderTarget.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/d3d/ImageD3D.h"
22#include "libGLESv2/renderer/d3d/TextureD3D.h"
23#include "libGLESv2/renderer/d3d/TextureStorage.h"
24
25namespace rx
26{
27
Brandon Jonesf47bebc2014-07-09 14:28:42 -070028bool IsRenderTargetUsage(GLenum usage)
29{
30 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
31}
32
Brandon Jones78b1acd2014-07-15 15:33:07 -070033TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070034 : mRenderer(renderer),
35 mUsage(GL_NONE),
36 mDirtyImages(true),
37 mImmutable(false)
38{
39}
40
41TextureD3D::~TextureD3D()
42{
43}
44
Brandon Jones6053a522014-07-25 16:22:09 -070045TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
46{
47 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
48 return static_cast<TextureD3D*>(texture);
49}
50
51TextureStorageInterface *TextureD3D::getNativeTexture()
52{
53 // ensure the underlying texture is created
54 initializeStorage(false);
55
56 TextureStorageInterface *storage = getBaseLevelStorage();
57 if (storage)
58 {
59 updateStorage();
60 }
61
62 return storage;
63}
64
Brandon Jonesf47bebc2014-07-09 14:28:42 -070065GLint TextureD3D::getBaseLevelWidth() const
66{
Brandon Jones78b1acd2014-07-15 15:33:07 -070067 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070068 return (baseImage ? baseImage->getWidth() : 0);
69}
70
71GLint TextureD3D::getBaseLevelHeight() const
72{
Brandon Jones78b1acd2014-07-15 15:33:07 -070073 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070074 return (baseImage ? baseImage->getHeight() : 0);
75}
76
77GLint TextureD3D::getBaseLevelDepth() const
78{
Brandon Jones78b1acd2014-07-15 15:33:07 -070079 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070080 return (baseImage ? baseImage->getDepth() : 0);
81}
82
83// Note: "base level image" is loosely defined to be any image from the base level,
84// where in the base of 2D array textures and cube maps there are several. Don't use
85// the base level image for anything except querying texture format and size.
86GLenum TextureD3D::getBaseLevelInternalFormat() const
87{
Brandon Jones78b1acd2014-07-15 15:33:07 -070088 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070089 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
90}
91
Brandon Jones78b1acd2014-07-15 15:33:07 -070092void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070093{
94 // No-op
95 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
96 {
97 return;
98 }
99
100 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
101 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
102 const void *pixelData = pixels;
103
104 if (unpack.pixelBuffer.id() != 0)
105 {
106 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
107 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
108 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
109 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
110 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
111 const void *bufferData = pixelBuffer->getImplementation()->getData();
112 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
113 }
114
115 if (pixelData != NULL)
116 {
117 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
118 mDirtyImages = true;
119 }
120}
121
122bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700123 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124{
125 const void *pixelData = pixels;
126
127 // CPU readback & copy where direct GPU copy is not supported
128 if (unpack.pixelBuffer.id() != 0)
129 {
130 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
131 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
132 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
133 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
134 const void *bufferData = pixelBuffer->getImplementation()->getData();
135 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
136 }
137
138 if (pixelData != NULL)
139 {
140 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
141 mDirtyImages = true;
142 }
143
144 return true;
145}
146
Brandon Jones78b1acd2014-07-15 15:33:07 -0700147void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
149 if (pixels != NULL)
150 {
151 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
152 mDirtyImages = true;
153 }
154}
155
156bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700157 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158{
159 if (pixels != NULL)
160 {
161 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
162 mDirtyImages = true;
163 }
164
165 return true;
166}
167
168bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
169{
170 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
171}
172
173bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700174 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700175{
176 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
177 {
178 return true;
179 }
180
181 // In order to perform the fast copy through the shader, we must have the right format, and be able
182 // to create a render target.
183 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
184
185 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
186
187 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
188}
189
190GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
191{
192 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
193 {
194 // Maximum number of levels
195 return gl::log2(std::max(std::max(width, height), depth)) + 1;
196 }
197 else
198 {
199 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
200 return 1;
201 }
202}
203
204int TextureD3D::mipLevels() const
205{
206 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
207}
208
209
Brandon Jones78b1acd2014-07-15 15:33:07 -0700210TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700212 mTexStorage(NULL)
213{
214 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
215 {
216 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
217 }
218}
219
220TextureD3D_2D::~TextureD3D_2D()
221{
Austin Kinross69822602014-08-12 15:51:37 -0700222 // Delete the Images before the TextureStorage.
223 // Images might be relying on the TextureStorage for some of their data.
224 // 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 -0700225 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
226 {
227 delete mImageArray[i];
228 }
Austin Kinross69822602014-08-12 15:51:37 -0700229
230 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
Brandon Jonescef06ff2014-08-05 13:27:48 -0700233Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700234{
235 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700236 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700237 return mImageArray[level];
238}
239
Brandon Jonescef06ff2014-08-05 13:27:48 -0700240GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700241{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700242 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
243 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700244}
245
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700246GLsizei TextureD3D_2D::getWidth(GLint level) const
247{
248 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
249 return mImageArray[level]->getWidth();
250 else
251 return 0;
252}
253
254GLsizei TextureD3D_2D::getHeight(GLint level) const
255{
256 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
257 return mImageArray[level]->getHeight();
258 else
259 return 0;
260}
261
262GLenum TextureD3D_2D::getInternalFormat(GLint level) const
263{
264 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
265 return mImageArray[level]->getInternalFormat();
266 else
267 return GL_NONE;
268}
269
270GLenum TextureD3D_2D::getActualFormat(GLint level) const
271{
272 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
273 return mImageArray[level]->getActualFormat();
274 else
275 return GL_NONE;
276}
277
278bool TextureD3D_2D::isDepth(GLint level) const
279{
Geoff Lang5d601382014-07-22 15:14:06 -0400280 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700281}
282
Brandon Jonescef06ff2014-08-05 13:27:48 -0700283void 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 -0700284{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700285 ASSERT(target == GL_TEXTURE_2D && depth == 1);
286
Geoff Lang5d601382014-07-22 15:14:06 -0400287 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
288
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700289 bool fastUnpacked = false;
290
Brandon Jonescef06ff2014-08-05 13:27:48 -0700291 redefineImage(level, sizedInternalFormat, width, height);
292
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700293 // Attempt a fast gpu copy of the pixel data to the surface
294 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
295 {
296 // Will try to create RT storage if it does not exist
Brandon Jonescef06ff2014-08-05 13:27:48 -0700297 RenderTarget *destRenderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700298 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
299
300 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
301 {
302 // Ensure we don't overwrite our newly initialized data
303 mImageArray[level]->markClean();
304
305 fastUnpacked = true;
306 }
307 }
308
309 if (!fastUnpacked)
310 {
311 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
312 }
313}
314
Brandon Jonescef06ff2014-08-05 13:27:48 -0700315void 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 -0700316{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700317 ASSERT(target == GL_TEXTURE_2D && depth == 1);
318
319 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
320 redefineImage(level, format, width, height);
321
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700322 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
323}
324
Brandon Jonescef06ff2014-08-05 13:27:48 -0700325void 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 -0700326{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700327 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
328
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700329 bool fastUnpacked = false;
330
331 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
332 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700333 RenderTarget *renderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700334 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
335
336 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
337 {
338 // Ensure we don't overwrite our newly initialized data
339 mImageArray[level]->markClean();
340
341 fastUnpacked = true;
342 }
343 }
344
345 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
346 {
347 commitRect(level, xoffset, yoffset, width, height);
348 }
349}
350
Brandon Jonescef06ff2014-08-05 13:27:48 -0700351void 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 -0700352{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700353 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
354
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700355 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
356 {
357 commitRect(level, xoffset, yoffset, width, height);
358 }
359}
360
Brandon Jonescef06ff2014-08-05 13:27:48 -0700361void 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 -0700362{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700363 ASSERT(target == GL_TEXTURE_2D);
364
365 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
366 redefineImage(level, sizedInternalFormat, width, height);
367
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700368 if (!mImageArray[level]->isRenderableFormat())
369 {
370 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
371 mDirtyImages = true;
372 }
373 else
374 {
375 ensureRenderTarget();
376 mImageArray[level]->markClean();
377
378 if (width != 0 && height != 0 && isValidLevel(level))
379 {
380 gl::Rectangle sourceRect;
381 sourceRect.x = x;
382 sourceRect.width = width;
383 sourceRect.y = y;
384 sourceRect.height = height;
385
386 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
387 }
388 }
389}
390
391void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
392{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700393 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
394
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700395 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
396 // the current level we're copying to is defined (with appropriate format, width & height)
397 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
398
399 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
400 {
401 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
402 mDirtyImages = true;
403 }
404 else
405 {
406 ensureRenderTarget();
407
408 if (isValidLevel(level))
409 {
410 updateStorageLevel(level);
411
412 gl::Rectangle sourceRect;
413 sourceRect.x = x;
414 sourceRect.width = width;
415 sourceRect.y = y;
416 sourceRect.height = height;
417
418 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400419 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700420 xoffset, yoffset, mTexStorage, level);
421 }
422 }
423}
424
Brandon Jonescef06ff2014-08-05 13:27:48 -0700425void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700426{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700427 ASSERT(target == GL_TEXTURE_2D && depth == 1);
428
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700429 for (int level = 0; level < levels; level++)
430 {
431 GLsizei levelWidth = std::max(1, width >> level);
432 GLsizei levelHeight = std::max(1, height >> level);
433 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
434 }
435
436 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
437 {
438 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
439 }
440
441 mImmutable = true;
442
Brandon Jones78b1acd2014-07-15 15:33:07 -0700443 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700444}
445
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700446void TextureD3D_2D::bindTexImage(egl::Surface *surface)
447{
448 GLenum internalformat = surface->getFormat();
449
450 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
451
452 if (mTexStorage)
453 {
454 SafeDelete(mTexStorage);
455 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700456 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700457
458 mDirtyImages = true;
459}
460
461void TextureD3D_2D::releaseTexImage()
462{
463 if (mTexStorage)
464 {
465 SafeDelete(mTexStorage);
466 }
467
468 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
469 {
470 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
471 }
472}
473
474void TextureD3D_2D::generateMipmaps()
475{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700476 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700477 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700478 for (int level = 1; level < levelCount; level++)
479 {
480 redefineImage(level, getBaseLevelInternalFormat(),
481 std::max(getBaseLevelWidth() >> level, 1),
482 std::max(getBaseLevelHeight() >> level, 1));
483 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700484
485 if (mTexStorage && mTexStorage->isRenderTarget())
486 {
487 for (int level = 1; level < levelCount; level++)
488 {
489 mTexStorage->generateMipmap(level);
490
491 mImageArray[level]->markClean();
492 }
493 }
494 else
495 {
496 for (int level = 1; level < levelCount; level++)
497 {
498 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
499 }
500 }
501}
502
Brandon Jonescef06ff2014-08-05 13:27:48 -0700503unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700504{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700505 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700506 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
507}
508
Brandon Jonescef06ff2014-08-05 13:27:48 -0700509RenderTarget *TextureD3D_2D::getRenderTarget(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700510{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700511 ASSERT(layer == 0);
512
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700513 // ensure the underlying texture is created
514 if (!ensureRenderTarget())
515 {
516 return NULL;
517 }
518
519 updateStorageLevel(level);
520
521 // ensure this is NOT a depth texture
522 if (isDepth(level))
523 {
524 return NULL;
525 }
526
527 return mTexStorage->getRenderTarget(level);
528}
529
Brandon Jonescef06ff2014-08-05 13:27:48 -0700530RenderTarget *TextureD3D_2D::getDepthStencil(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532 ASSERT(layer == 0);
533
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534 // ensure the underlying texture is created
535 if (!ensureRenderTarget())
536 {
537 return NULL;
538 }
539
540 updateStorageLevel(level);
541
542 // ensure this is actually a depth texture
543 if (!isDepth(level))
544 {
545 return NULL;
546 }
547
548 return mTexStorage->getRenderTarget(level);
549}
550
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551bool TextureD3D_2D::isValidLevel(int level) const
552{
553 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
554}
555
556bool TextureD3D_2D::isLevelComplete(int level) const
557{
558 if (isImmutable())
559 {
560 return true;
561 }
562
Brandon Jones78b1acd2014-07-15 15:33:07 -0700563 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700564
565 GLsizei width = baseImage->getWidth();
566 GLsizei height = baseImage->getHeight();
567
568 if (width <= 0 || height <= 0)
569 {
570 return false;
571 }
572
573 // The base image level is complete if the width and height are positive
574 if (level == 0)
575 {
576 return true;
577 }
578
579 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700580 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700581
582 if (image->getInternalFormat() != baseImage->getInternalFormat())
583 {
584 return false;
585 }
586
587 if (image->getWidth() != std::max(1, width >> level))
588 {
589 return false;
590 }
591
592 if (image->getHeight() != std::max(1, height >> level))
593 {
594 return false;
595 }
596
597 return true;
598}
599
600// Constructs a native texture resource from the texture images
601void TextureD3D_2D::initializeStorage(bool renderTarget)
602{
603 // Only initialize the first time this texture is used as a render target or shader resource
604 if (mTexStorage)
605 {
606 return;
607 }
608
609 // do not attempt to create storage for nonexistant data
610 if (!isLevelComplete(0))
611 {
612 return;
613 }
614
615 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
616
617 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
618 ASSERT(mTexStorage);
619
620 // flush image data to the storage
621 updateStorage();
622}
623
Brandon Jones78b1acd2014-07-15 15:33:07 -0700624TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625{
626 GLsizei width = getBaseLevelWidth();
627 GLsizei height = getBaseLevelHeight();
628
629 ASSERT(width > 0 && height > 0);
630
631 // use existing storage level count, when previously specified by TexStorage*D
632 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
633
Brandon Jones78b1acd2014-07-15 15:33:07 -0700634 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635}
636
637void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
638{
639 SafeDelete(mTexStorage);
640 mTexStorage = newCompleteTexStorage;
641
642 if (mTexStorage && mTexStorage->isManaged())
643 {
644 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
645 {
646 mImageArray[level]->setManagedSurface(mTexStorage, level);
647 }
648 }
649
650 mDirtyImages = true;
651}
652
653void TextureD3D_2D::updateStorage()
654{
655 ASSERT(mTexStorage != NULL);
656 GLint storageLevels = mTexStorage->getLevelCount();
657 for (int level = 0; level < storageLevels; level++)
658 {
659 if (mImageArray[level]->isDirty() && isLevelComplete(level))
660 {
661 updateStorageLevel(level);
662 }
663 }
664}
665
666bool TextureD3D_2D::ensureRenderTarget()
667{
668 initializeStorage(true);
669
670 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
671 {
672 ASSERT(mTexStorage);
673 if (!mTexStorage->isRenderTarget())
674 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700675 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700676
677 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
678 {
679 delete newRenderTargetStorage;
680 return gl::error(GL_OUT_OF_MEMORY, false);
681 }
682
683 setCompleteTexStorage(newRenderTargetStorage);
684 }
685 }
686
687 return (mTexStorage && mTexStorage->isRenderTarget());
688}
689
690TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
691{
692 return mTexStorage;
693}
694
695const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
696{
697 return mImageArray[0];
698}
699
700void TextureD3D_2D::updateStorageLevel(int level)
701{
702 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
703 ASSERT(isLevelComplete(level));
704
705 if (mImageArray[level]->isDirty())
706 {
707 commitRect(level, 0, 0, getWidth(level), getHeight(level));
708 }
709}
710
711void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
712{
713 // If there currently is a corresponding storage texture image, it has these parameters
714 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
715 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
716 const GLenum storageFormat = getBaseLevelInternalFormat();
717
718 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
719
720 if (mTexStorage)
721 {
722 const int storageLevels = mTexStorage->getLevelCount();
723
724 if ((level >= storageLevels && storageLevels != 0) ||
725 width != storageWidth ||
726 height != storageHeight ||
727 internalformat != storageFormat) // Discard mismatched storage
728 {
729 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
730 {
731 mImageArray[i]->markDirty();
732 }
733
734 SafeDelete(mTexStorage);
735 mDirtyImages = true;
736 }
737 }
738}
739
740void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
741{
742 if (isValidLevel(level))
743 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700744 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700745 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
746 {
747 image->markClean();
748 }
749 }
750}
751
Brandon Jones0511e802014-07-14 16:27:26 -0700752
Brandon Jones78b1acd2014-07-15 15:33:07 -0700753TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700754 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700755 mTexStorage(NULL)
756{
757 for (int i = 0; i < 6; i++)
758 {
759 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
760 {
761 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
762 }
763 }
764}
765
766TextureD3D_Cube::~TextureD3D_Cube()
767{
Austin Kinross69822602014-08-12 15:51:37 -0700768 // Delete the Images before the TextureStorage.
769 // Images might be relying on the TextureStorage for some of their data.
770 // 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 -0700771 for (int i = 0; i < 6; i++)
772 {
773 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
774 {
775 SafeDelete(mImageArray[i][j]);
776 }
777 }
Austin Kinross69822602014-08-12 15:51:37 -0700778
779 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700780}
781
Brandon Jonescef06ff2014-08-05 13:27:48 -0700782Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700783{
784 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700785 ASSERT(layer < 6);
786 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700787}
788
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700790{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700791 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
792 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700793}
794
Brandon Jonescef06ff2014-08-05 13:27:48 -0700795GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700796{
797 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700798 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700799 else
800 return GL_NONE;
801}
802
Brandon Jonescef06ff2014-08-05 13:27:48 -0700803bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700804{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700805 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700806}
807
Brandon Jonescef06ff2014-08-05 13:27:48 -0700808void 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 -0700809{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700810 ASSERT(depth == 1);
811
812 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400813 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700814
815 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
816
817 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
818}
819
Brandon Jonescef06ff2014-08-05 13:27:48 -0700820void 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 -0700821{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700822 ASSERT(depth == 1);
823
Brandon Jones0511e802014-07-14 16:27:26 -0700824 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700825 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
826
Brandon Jones0511e802014-07-14 16:27:26 -0700827 redefineImage(faceIndex, level, format, width, height);
828
829 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
830}
831
Brandon Jonescef06ff2014-08-05 13:27:48 -0700832void 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 -0700833{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700834 ASSERT(depth == 1 && zoffset == 0);
835
836 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
837
Brandon Jones0511e802014-07-14 16:27:26 -0700838 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
839 {
840 commitRect(faceIndex, level, xoffset, yoffset, width, height);
841 }
842}
843
Brandon Jonescef06ff2014-08-05 13:27:48 -0700844void 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 -0700845{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700846 ASSERT(depth == 1 && zoffset == 0);
847
848 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
849
Brandon Jones0511e802014-07-14 16:27:26 -0700850 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
851 {
852 commitRect(faceIndex, level, xoffset, yoffset, width, height);
853 }
854}
855
856void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
857{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700858 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400859 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
860
Brandon Jones0511e802014-07-14 16:27:26 -0700861 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
862
863 if (!mImageArray[faceIndex][level]->isRenderableFormat())
864 {
865 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
866 mDirtyImages = true;
867 }
868 else
869 {
870 ensureRenderTarget();
871 mImageArray[faceIndex][level]->markClean();
872
873 ASSERT(width == height);
874
875 if (width > 0 && isValidFaceLevel(faceIndex, level))
876 {
877 gl::Rectangle sourceRect;
878 sourceRect.x = x;
879 sourceRect.width = width;
880 sourceRect.y = y;
881 sourceRect.height = height;
882
883 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
884 }
885 }
886}
887
888void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
889{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700890 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700891
892 // We can only make our texture storage to a render target if the level we're copying *to* is complete
893 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
894 // rely on the "getBaseLevel*" methods reliably otherwise.
895 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
896
897 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
898 {
899 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
900 mDirtyImages = true;
901 }
902 else
903 {
904 ensureRenderTarget();
905
906 if (isValidFaceLevel(faceIndex, level))
907 {
908 updateStorageFaceLevel(faceIndex, level);
909
910 gl::Rectangle sourceRect;
911 sourceRect.x = x;
912 sourceRect.width = width;
913 sourceRect.y = y;
914 sourceRect.height = height;
915
Geoff Lang5d601382014-07-22 15:14:06 -0400916 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700917 xoffset, yoffset, mTexStorage, target, level);
918 }
919 }
920}
921
Brandon Jonescef06ff2014-08-05 13:27:48 -0700922void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700923{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924 ASSERT(width == height);
925 ASSERT(depth == 1);
926
Brandon Jones0511e802014-07-14 16:27:26 -0700927 for (int level = 0; level < levels; level++)
928 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700929 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700930 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
931 {
932 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
933 }
934 }
935
936 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
937 {
938 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
939 {
940 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
941 }
942 }
943
944 mImmutable = true;
945
Brandon Jonescef06ff2014-08-05 13:27:48 -0700946 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700947}
948
Brandon Jones0511e802014-07-14 16:27:26 -0700949// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
950bool TextureD3D_Cube::isCubeComplete() const
951{
952 int baseWidth = getBaseLevelWidth();
953 int baseHeight = getBaseLevelHeight();
954 GLenum baseFormat = getBaseLevelInternalFormat();
955
956 if (baseWidth <= 0 || baseWidth != baseHeight)
957 {
958 return false;
959 }
960
961 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
962 {
963 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
964
965 if (faceBaseImage.getWidth() != baseWidth ||
966 faceBaseImage.getHeight() != baseHeight ||
967 faceBaseImage.getInternalFormat() != baseFormat )
968 {
969 return false;
970 }
971 }
972
973 return true;
974}
975
Brandon Jones6053a522014-07-25 16:22:09 -0700976void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
977{
978 UNREACHABLE();
979}
980
981void TextureD3D_Cube::releaseTexImage()
982{
983 UNREACHABLE();
984}
985
986
Brandon Jones0511e802014-07-14 16:27:26 -0700987void TextureD3D_Cube::generateMipmaps()
988{
989 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
990 int levelCount = mipLevels();
991 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
992 {
993 for (int level = 1; level < levelCount; level++)
994 {
995 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
996 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
997 }
998 }
999
1000 if (mTexStorage && mTexStorage->isRenderTarget())
1001 {
1002 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1003 {
1004 for (int level = 1; level < levelCount; level++)
1005 {
1006 mTexStorage->generateMipmap(faceIndex, level);
1007
1008 mImageArray[faceIndex][level]->markClean();
1009 }
1010 }
1011 }
1012 else
1013 {
1014 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1015 {
1016 for (int level = 1; level < levelCount; level++)
1017 {
1018 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1019 }
1020 }
1021 }
1022}
1023
Brandon Jonescef06ff2014-08-05 13:27:48 -07001024unsigned int TextureD3D_Cube::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001025{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001026 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001027 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1028}
1029
Brandon Jonescef06ff2014-08-05 13:27:48 -07001030RenderTarget *TextureD3D_Cube::getRenderTarget(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001031{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001032 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001033 ASSERT(gl::IsCubemapTextureTarget(target));
1034
1035 // ensure the underlying texture is created
1036 if (!ensureRenderTarget())
1037 {
1038 return NULL;
1039 }
1040
Brandon Jonescef06ff2014-08-05 13:27:48 -07001041 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001042
1043 // ensure this is NOT a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001044 if (isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001045 {
1046 return NULL;
1047 }
1048
1049 return mTexStorage->getRenderTarget(target, level);
1050}
1051
Brandon Jonescef06ff2014-08-05 13:27:48 -07001052RenderTarget *TextureD3D_Cube::getDepthStencil(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001053{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001054 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001055 ASSERT(gl::IsCubemapTextureTarget(target));
1056
1057 // ensure the underlying texture is created
1058 if (!ensureRenderTarget())
1059 {
1060 return NULL;
1061 }
1062
Brandon Jonescef06ff2014-08-05 13:27:48 -07001063 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001064
1065 // ensure this is a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001066 if (!isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001067 {
1068 return NULL;
1069 }
1070
1071 return mTexStorage->getRenderTarget(target, level);
1072}
1073
Brandon Jones0511e802014-07-14 16:27:26 -07001074void TextureD3D_Cube::initializeStorage(bool renderTarget)
1075{
1076 // Only initialize the first time this texture is used as a render target or shader resource
1077 if (mTexStorage)
1078 {
1079 return;
1080 }
1081
1082 // do not attempt to create storage for nonexistant data
1083 if (!isFaceLevelComplete(0, 0))
1084 {
1085 return;
1086 }
1087
1088 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1089
1090 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1091 ASSERT(mTexStorage);
1092
1093 // flush image data to the storage
1094 updateStorage();
1095}
1096
1097TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1098{
1099 GLsizei size = getBaseLevelWidth();
1100
1101 ASSERT(size > 0);
1102
1103 // use existing storage level count, when previously specified by TexStorage*D
1104 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1105
1106 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1107}
1108
1109void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1110{
1111 SafeDelete(mTexStorage);
1112 mTexStorage = newCompleteTexStorage;
1113
1114 if (mTexStorage && mTexStorage->isManaged())
1115 {
1116 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1117 {
1118 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1119 {
1120 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1121 }
1122 }
1123 }
1124
1125 mDirtyImages = true;
1126}
1127
1128void TextureD3D_Cube::updateStorage()
1129{
1130 ASSERT(mTexStorage != NULL);
1131 GLint storageLevels = mTexStorage->getLevelCount();
1132 for (int face = 0; face < 6; face++)
1133 {
1134 for (int level = 0; level < storageLevels; level++)
1135 {
1136 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1137 {
1138 updateStorageFaceLevel(face, level);
1139 }
1140 }
1141 }
1142}
1143
1144bool TextureD3D_Cube::ensureRenderTarget()
1145{
1146 initializeStorage(true);
1147
1148 if (getBaseLevelWidth() > 0)
1149 {
1150 ASSERT(mTexStorage);
1151 if (!mTexStorage->isRenderTarget())
1152 {
1153 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1154
1155 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1156 {
1157 delete newRenderTargetStorage;
1158 return gl::error(GL_OUT_OF_MEMORY, false);
1159 }
1160
1161 setCompleteTexStorage(newRenderTargetStorage);
1162 }
1163 }
1164
1165 return (mTexStorage && mTexStorage->isRenderTarget());
1166}
1167
1168TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1169{
1170 return mTexStorage;
1171}
1172
1173const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1174{
1175 // Note: if we are not cube-complete, there is no single base level image that can describe all
1176 // cube faces, so this method is only well-defined for a cube-complete base level.
1177 return mImageArray[0][0];
1178}
1179
Brandon Jones0511e802014-07-14 16:27:26 -07001180bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1181{
1182 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1183}
1184
Brandon Jones0511e802014-07-14 16:27:26 -07001185bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1186{
1187 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1188
1189 if (isImmutable())
1190 {
1191 return true;
1192 }
1193
1194 int baseSize = getBaseLevelWidth();
1195
1196 if (baseSize <= 0)
1197 {
1198 return false;
1199 }
1200
1201 // "isCubeComplete" checks for base level completeness and we must call that
1202 // to determine if any face at level 0 is complete. We omit that check here
1203 // to avoid re-checking cube-completeness for every face at level 0.
1204 if (level == 0)
1205 {
1206 return true;
1207 }
1208
1209 // Check that non-zero levels are consistent with the base level.
1210 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1211
1212 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1213 {
1214 return false;
1215 }
1216
1217 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1218 {
1219 return false;
1220 }
1221
1222 return true;
1223}
1224
1225void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1226{
1227 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1228 ImageD3D *image = mImageArray[faceIndex][level];
1229
1230 if (image->isDirty())
1231 {
1232 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1233 }
1234}
1235
1236void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1237{
1238 // If there currently is a corresponding storage texture image, it has these parameters
1239 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1240 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1241 const GLenum storageFormat = getBaseLevelInternalFormat();
1242
1243 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1244
1245 if (mTexStorage)
1246 {
1247 const int storageLevels = mTexStorage->getLevelCount();
1248
1249 if ((level >= storageLevels && storageLevels != 0) ||
1250 width != storageWidth ||
1251 height != storageHeight ||
1252 internalformat != storageFormat) // Discard mismatched storage
1253 {
1254 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1255 {
1256 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1257 {
1258 mImageArray[faceIndex][level]->markDirty();
1259 }
1260 }
1261
1262 SafeDelete(mTexStorage);
1263
1264 mDirtyImages = true;
1265 }
1266 }
1267}
1268
1269void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1270{
1271 if (isValidFaceLevel(faceIndex, level))
1272 {
1273 ImageD3D *image = mImageArray[faceIndex][level];
1274 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1275 image->markClean();
1276 }
1277}
1278
Brandon Jones78b1acd2014-07-15 15:33:07 -07001279
1280TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001281 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001282 mTexStorage(NULL)
1283{
1284 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1285 {
1286 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1287 }
1288}
1289
1290TextureD3D_3D::~TextureD3D_3D()
1291{
Austin Kinross69822602014-08-12 15:51:37 -07001292 // Delete the Images before the TextureStorage.
1293 // Images might be relying on the TextureStorage for some of their data.
1294 // 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 -07001295 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1296 {
1297 delete mImageArray[i];
1298 }
Austin Kinross69822602014-08-12 15:51:37 -07001299
1300 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001301}
1302
Brandon Jonescef06ff2014-08-05 13:27:48 -07001303Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001304{
1305 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001306 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001307 return mImageArray[level];
1308}
1309
Brandon Jonescef06ff2014-08-05 13:27:48 -07001310GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001311{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001312 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1313 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001314}
1315
Brandon Jones78b1acd2014-07-15 15:33:07 -07001316GLsizei TextureD3D_3D::getWidth(GLint level) const
1317{
1318 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1319 return mImageArray[level]->getWidth();
1320 else
1321 return 0;
1322}
1323
1324GLsizei TextureD3D_3D::getHeight(GLint level) const
1325{
1326 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1327 return mImageArray[level]->getHeight();
1328 else
1329 return 0;
1330}
1331
1332GLsizei TextureD3D_3D::getDepth(GLint level) const
1333{
1334 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1335 return mImageArray[level]->getDepth();
1336 else
1337 return 0;
1338}
1339
1340GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1341{
1342 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1343 return mImageArray[level]->getInternalFormat();
1344 else
1345 return GL_NONE;
1346}
1347
1348bool TextureD3D_3D::isDepth(GLint level) const
1349{
Geoff Lang5d601382014-07-22 15:14:06 -04001350 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001351}
1352
Brandon Jonescef06ff2014-08-05 13:27:48 -07001353void 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 -07001354{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001355 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001356 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1357
Brandon Jones78b1acd2014-07-15 15:33:07 -07001358 redefineImage(level, sizedInternalFormat, width, height, depth);
1359
1360 bool fastUnpacked = false;
1361
1362 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1363 if (isFastUnpackable(unpack, sizedInternalFormat))
1364 {
1365 // Will try to create RT storage if it does not exist
1366 RenderTarget *destRenderTarget = getRenderTarget(level);
1367 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1368
1369 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1370 {
1371 // Ensure we don't overwrite our newly initialized data
1372 mImageArray[level]->markClean();
1373
1374 fastUnpacked = true;
1375 }
1376 }
1377
1378 if (!fastUnpacked)
1379 {
1380 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1381 }
1382}
1383
Brandon Jonescef06ff2014-08-05 13:27:48 -07001384void 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 -07001385{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001386 ASSERT(target == GL_TEXTURE_3D);
1387
Brandon Jones78b1acd2014-07-15 15:33:07 -07001388 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1389 redefineImage(level, format, width, height, depth);
1390
1391 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1392}
1393
Brandon Jonescef06ff2014-08-05 13:27:48 -07001394void 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 -07001395{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001396 ASSERT(target == GL_TEXTURE_3D);
1397
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398 bool fastUnpacked = false;
1399
1400 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1401 if (isFastUnpackable(unpack, getInternalFormat(level)))
1402 {
1403 RenderTarget *destRenderTarget = getRenderTarget(level);
1404 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1405
1406 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1407 {
1408 // Ensure we don't overwrite our newly initialized data
1409 mImageArray[level]->markClean();
1410
1411 fastUnpacked = true;
1412 }
1413 }
1414
1415 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1416 {
1417 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1418 }
1419}
1420
Brandon Jonescef06ff2014-08-05 13:27:48 -07001421void 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 -07001422{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001423 ASSERT(target == GL_TEXTURE_3D);
1424
Brandon Jones78b1acd2014-07-15 15:33:07 -07001425 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1426 {
1427 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1428 }
1429}
1430
Brandon Jonescef06ff2014-08-05 13:27:48 -07001431void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1432{
1433 UNIMPLEMENTED();
1434}
1435
Brandon Jones78b1acd2014-07-15 15:33:07 -07001436void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1437{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001438 ASSERT(target == GL_TEXTURE_3D);
1439
Brandon Jones78b1acd2014-07-15 15:33:07 -07001440 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1441 // the current level we're copying to is defined (with appropriate format, width & height)
1442 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1443
1444 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1445 {
1446 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1447 mDirtyImages = true;
1448 }
1449 else
1450 {
1451 ensureRenderTarget();
1452
1453 if (isValidLevel(level))
1454 {
1455 updateStorageLevel(level);
1456
1457 gl::Rectangle sourceRect;
1458 sourceRect.x = x;
1459 sourceRect.width = width;
1460 sourceRect.y = y;
1461 sourceRect.height = height;
1462
1463 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001464 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001465 xoffset, yoffset, zoffset, mTexStorage, level);
1466 }
1467 }
1468}
1469
Brandon Jonescef06ff2014-08-05 13:27:48 -07001470void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001472 ASSERT(target == GL_TEXTURE_3D);
1473
Brandon Jones78b1acd2014-07-15 15:33:07 -07001474 for (int level = 0; level < levels; level++)
1475 {
1476 GLsizei levelWidth = std::max(1, width >> level);
1477 GLsizei levelHeight = std::max(1, height >> level);
1478 GLsizei levelDepth = std::max(1, depth >> level);
1479 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1480 }
1481
1482 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1483 {
1484 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1485 }
1486
1487 mImmutable = true;
1488
1489 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1490}
1491
Brandon Jones6053a522014-07-25 16:22:09 -07001492void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001493{
Brandon Jones6053a522014-07-25 16:22:09 -07001494 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495}
1496
Brandon Jones6053a522014-07-25 16:22:09 -07001497void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001498{
Brandon Jones6053a522014-07-25 16:22:09 -07001499 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500}
1501
Brandon Jones6053a522014-07-25 16:22:09 -07001502
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503void TextureD3D_3D::generateMipmaps()
1504{
1505 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1506 int levelCount = mipLevels();
1507 for (int level = 1; level < levelCount; level++)
1508 {
1509 redefineImage(level, getBaseLevelInternalFormat(),
1510 std::max(getBaseLevelWidth() >> level, 1),
1511 std::max(getBaseLevelHeight() >> level, 1),
1512 std::max(getBaseLevelDepth() >> level, 1));
1513 }
1514
1515 if (mTexStorage && mTexStorage->isRenderTarget())
1516 {
1517 for (int level = 1; level < levelCount; level++)
1518 {
1519 mTexStorage->generateMipmap(level);
1520
1521 mImageArray[level]->markClean();
1522 }
1523 }
1524 else
1525 {
1526 for (int level = 1; level < levelCount; level++)
1527 {
1528 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1529 }
1530 }
1531}
1532
1533unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1534{
1535 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1536}
1537
1538RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1539{
1540 // ensure the underlying texture is created
1541 if (!ensureRenderTarget())
1542 {
1543 return NULL;
1544 }
1545
1546 updateStorageLevel(level);
1547
1548 // ensure this is NOT a depth texture
1549 if (isDepth(level))
1550 {
1551 return NULL;
1552 }
1553
1554 return mTexStorage->getRenderTarget(level);
1555}
1556
1557RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1558{
1559 // ensure the underlying texture is created
1560 if (!ensureRenderTarget())
1561 {
1562 return NULL;
1563 }
1564
1565 updateStorage();
1566
1567 // ensure this is NOT a depth texture
1568 if (isDepth(level))
1569 {
1570 return NULL;
1571 }
1572
1573 return mTexStorage->getRenderTarget(level, layer);
1574}
1575
1576RenderTarget *TextureD3D_3D::getDepthStencil(GLint level, GLint layer)
1577{
1578 // ensure the underlying texture is created
1579 if (!ensureRenderTarget())
1580 {
1581 return NULL;
1582 }
1583
1584 updateStorageLevel(level);
1585
1586 // ensure this is a depth texture
1587 if (!isDepth(level))
1588 {
1589 return NULL;
1590 }
1591
1592 return mTexStorage->getRenderTarget(level, layer);
1593}
1594
1595void TextureD3D_3D::initializeStorage(bool renderTarget)
1596{
1597 // Only initialize the first time this texture is used as a render target or shader resource
1598 if (mTexStorage)
1599 {
1600 return;
1601 }
1602
1603 // do not attempt to create storage for nonexistant data
1604 if (!isLevelComplete(0))
1605 {
1606 return;
1607 }
1608
1609 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1610
1611 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1612 ASSERT(mTexStorage);
1613
1614 // flush image data to the storage
1615 updateStorage();
1616}
1617
1618TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1619{
1620 GLsizei width = getBaseLevelWidth();
1621 GLsizei height = getBaseLevelHeight();
1622 GLsizei depth = getBaseLevelDepth();
1623
1624 ASSERT(width > 0 && height > 0 && depth > 0);
1625
1626 // use existing storage level count, when previously specified by TexStorage*D
1627 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1628
1629 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1630}
1631
1632void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1633{
1634 SafeDelete(mTexStorage);
1635 mTexStorage = newCompleteTexStorage;
1636 mDirtyImages = true;
1637
1638 // We do not support managed 3D storage, as that is D3D9/ES2-only
1639 ASSERT(!mTexStorage->isManaged());
1640}
1641
1642void TextureD3D_3D::updateStorage()
1643{
1644 ASSERT(mTexStorage != NULL);
1645 GLint storageLevels = mTexStorage->getLevelCount();
1646 for (int level = 0; level < storageLevels; level++)
1647 {
1648 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1649 {
1650 updateStorageLevel(level);
1651 }
1652 }
1653}
1654
1655bool TextureD3D_3D::ensureRenderTarget()
1656{
1657 initializeStorage(true);
1658
1659 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1660 {
1661 ASSERT(mTexStorage);
1662 if (!mTexStorage->isRenderTarget())
1663 {
1664 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1665
1666 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1667 {
1668 delete newRenderTargetStorage;
1669 return gl::error(GL_OUT_OF_MEMORY, false);
1670 }
1671
1672 setCompleteTexStorage(newRenderTargetStorage);
1673 }
1674 }
1675
1676 return (mTexStorage && mTexStorage->isRenderTarget());
1677}
1678
1679TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1680{
1681 return mTexStorage;
1682}
1683
1684const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1685{
1686 return mImageArray[0];
1687}
1688
1689bool TextureD3D_3D::isValidLevel(int level) const
1690{
1691 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1692}
1693
1694bool TextureD3D_3D::isLevelComplete(int level) const
1695{
1696 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1697
1698 if (isImmutable())
1699 {
1700 return true;
1701 }
1702
1703 GLsizei width = getBaseLevelWidth();
1704 GLsizei height = getBaseLevelHeight();
1705 GLsizei depth = getBaseLevelDepth();
1706
1707 if (width <= 0 || height <= 0 || depth <= 0)
1708 {
1709 return false;
1710 }
1711
1712 if (level == 0)
1713 {
1714 return true;
1715 }
1716
1717 ImageD3D *levelImage = mImageArray[level];
1718
1719 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1720 {
1721 return false;
1722 }
1723
1724 if (levelImage->getWidth() != std::max(1, width >> level))
1725 {
1726 return false;
1727 }
1728
1729 if (levelImage->getHeight() != std::max(1, height >> level))
1730 {
1731 return false;
1732 }
1733
1734 if (levelImage->getDepth() != std::max(1, depth >> level))
1735 {
1736 return false;
1737 }
1738
1739 return true;
1740}
1741
1742void TextureD3D_3D::updateStorageLevel(int level)
1743{
1744 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1745 ASSERT(isLevelComplete(level));
1746
1747 if (mImageArray[level]->isDirty())
1748 {
1749 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1750 }
1751}
1752
1753void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1754{
1755 // If there currently is a corresponding storage texture image, it has these parameters
1756 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1757 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1758 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1759 const GLenum storageFormat = getBaseLevelInternalFormat();
1760
1761 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1762
1763 if (mTexStorage)
1764 {
1765 const int storageLevels = mTexStorage->getLevelCount();
1766
1767 if ((level >= storageLevels && storageLevels != 0) ||
1768 width != storageWidth ||
1769 height != storageHeight ||
1770 depth != storageDepth ||
1771 internalformat != storageFormat) // Discard mismatched storage
1772 {
1773 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1774 {
1775 mImageArray[i]->markDirty();
1776 }
1777
1778 SafeDelete(mTexStorage);
1779 mDirtyImages = true;
1780 }
1781 }
1782}
1783
1784void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1785{
1786 if (isValidLevel(level))
1787 {
1788 ImageD3D *image = mImageArray[level];
1789 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1790 {
1791 image->markClean();
1792 }
1793 }
1794}
1795
Brandon Jones142ec422014-07-16 10:31:30 -07001796
1797TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001798 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001799 mTexStorage(NULL)
1800{
1801 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1802 {
1803 mLayerCounts[level] = 0;
1804 mImageArray[level] = NULL;
1805 }
1806}
1807
1808TextureD3D_2DArray::~TextureD3D_2DArray()
1809{
Austin Kinross69822602014-08-12 15:51:37 -07001810 // Delete the Images before the TextureStorage.
1811 // Images might be relying on the TextureStorage for some of their data.
1812 // 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 -07001813 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001814 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001815}
1816
Brandon Jones142ec422014-07-16 10:31:30 -07001817Image *TextureD3D_2DArray::getImage(int level, int layer) const
1818{
1819 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1820 ASSERT(layer < mLayerCounts[level]);
1821 return mImageArray[level][layer];
1822}
1823
1824GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1825{
1826 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1827 return mLayerCounts[level];
1828}
1829
Brandon Jones142ec422014-07-16 10:31:30 -07001830GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1831{
1832 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1833}
1834
1835GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1836{
1837 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1838}
1839
1840GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1841{
1842 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1843}
1844
1845GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1846{
1847 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1848}
1849
1850bool TextureD3D_2DArray::isDepth(GLint level) const
1851{
Geoff Lang5d601382014-07-22 15:14:06 -04001852 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001853}
1854
Brandon Jonescef06ff2014-08-05 13:27:48 -07001855void 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 -07001856{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001857 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1858
Geoff Lang5d601382014-07-22 15:14:06 -04001859 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1860
Brandon Jones142ec422014-07-16 10:31:30 -07001861 redefineImage(level, sizedInternalFormat, width, height, depth);
1862
Geoff Lang5d601382014-07-22 15:14:06 -04001863 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1864 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001865
1866 for (int i = 0; i < depth; i++)
1867 {
1868 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1869 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1870 }
1871}
1872
Brandon Jonescef06ff2014-08-05 13:27:48 -07001873void 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 -07001874{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001875 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1876
Brandon Jones142ec422014-07-16 10:31:30 -07001877 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1878 redefineImage(level, format, width, height, depth);
1879
Geoff Lang5d601382014-07-22 15:14:06 -04001880 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1881 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001882
1883 for (int i = 0; i < depth; i++)
1884 {
1885 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1886 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1887 }
1888}
1889
Brandon Jonescef06ff2014-08-05 13:27:48 -07001890void 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 -07001891{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001892 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1893
Geoff Lang5d601382014-07-22 15:14:06 -04001894 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1895 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001896
1897 for (int i = 0; i < depth; i++)
1898 {
1899 int layer = zoffset + i;
1900 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1901
1902 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
1903 {
1904 commitRect(level, xoffset, yoffset, layer, width, height);
1905 }
1906 }
1907}
1908
Brandon Jonescef06ff2014-08-05 13:27:48 -07001909void 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 -07001910{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001911 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1912
Geoff Lang5d601382014-07-22 15:14:06 -04001913 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1914 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001915
1916 for (int i = 0; i < depth; i++)
1917 {
1918 int layer = zoffset + i;
1919 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1920
1921 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1922 {
1923 commitRect(level, xoffset, yoffset, layer, width, height);
1924 }
1925 }
1926}
1927
Brandon Jonescef06ff2014-08-05 13:27:48 -07001928void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1929{
1930 UNIMPLEMENTED();
1931}
1932
Brandon Jones142ec422014-07-16 10:31:30 -07001933void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1934{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001935 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1936
Brandon Jones142ec422014-07-16 10:31:30 -07001937 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1938 // the current level we're copying to is defined (with appropriate format, width & height)
1939 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1940
1941 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1942 {
1943 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1944 mDirtyImages = true;
1945 }
1946 else
1947 {
1948 ensureRenderTarget();
1949
1950 if (isValidLevel(level))
1951 {
1952 updateStorageLevel(level);
1953
1954 gl::Rectangle sourceRect;
1955 sourceRect.x = x;
1956 sourceRect.width = width;
1957 sourceRect.y = y;
1958 sourceRect.height = height;
1959
Geoff Lang5d601382014-07-22 15:14:06 -04001960 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001961 xoffset, yoffset, zoffset, mTexStorage, level);
1962 }
1963 }
1964}
1965
Brandon Jonescef06ff2014-08-05 13:27:48 -07001966void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001967{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001968 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1969
Brandon Jones142ec422014-07-16 10:31:30 -07001970 deleteImages();
1971
1972 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1973 {
1974 GLsizei levelWidth = std::max(1, width >> level);
1975 GLsizei levelHeight = std::max(1, height >> level);
1976
1977 mLayerCounts[level] = (level < levels ? depth : 0);
1978
1979 if (mLayerCounts[level] > 0)
1980 {
1981 // Create new images for this level
1982 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1983
1984 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1985 {
1986 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1987 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1988 levelHeight, 1, true);
1989 }
1990 }
1991 }
1992
1993 mImmutable = true;
1994 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1995}
1996
Brandon Jones6053a522014-07-25 16:22:09 -07001997void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001998{
Brandon Jones6053a522014-07-25 16:22:09 -07001999 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002000}
2001
Brandon Jones6053a522014-07-25 16:22:09 -07002002void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002003{
Brandon Jones6053a522014-07-25 16:22:09 -07002004 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002005}
2006
Brandon Jones6053a522014-07-25 16:22:09 -07002007
Brandon Jones142ec422014-07-16 10:31:30 -07002008void TextureD3D_2DArray::generateMipmaps()
2009{
2010 int baseWidth = getBaseLevelWidth();
2011 int baseHeight = getBaseLevelHeight();
2012 int baseDepth = getBaseLevelDepth();
2013 GLenum baseFormat = getBaseLevelInternalFormat();
2014
2015 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2016 int levelCount = mipLevels();
2017 for (int level = 1; level < levelCount; level++)
2018 {
2019 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2020 }
2021
2022 if (mTexStorage && mTexStorage->isRenderTarget())
2023 {
2024 for (int level = 1; level < levelCount; level++)
2025 {
2026 mTexStorage->generateMipmap(level);
2027
2028 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2029 {
2030 mImageArray[level][layer]->markClean();
2031 }
2032 }
2033 }
2034 else
2035 {
2036 for (int level = 1; level < levelCount; level++)
2037 {
2038 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2039 {
2040 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2041 }
2042 }
2043 }
2044}
2045
2046unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2047{
2048 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2049}
2050
2051RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2052{
2053 // ensure the underlying texture is created
2054 if (!ensureRenderTarget())
2055 {
2056 return NULL;
2057 }
2058
2059 updateStorageLevel(level);
2060
2061 // ensure this is NOT a depth texture
2062 if (isDepth(level))
2063 {
2064 return NULL;
2065 }
2066
2067 return mTexStorage->getRenderTarget(level, layer);
2068}
2069
2070RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer)
2071{
2072 // ensure the underlying texture is created
2073 if (!ensureRenderTarget())
2074 {
2075 return NULL;
2076 }
2077
2078 updateStorageLevel(level);
2079
2080 // ensure this is a depth texture
2081 if (!isDepth(level))
2082 {
2083 return NULL;
2084 }
2085
2086 return mTexStorage->getRenderTarget(level, layer);
2087}
2088
2089void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2090{
2091 // Only initialize the first time this texture is used as a render target or shader resource
2092 if (mTexStorage)
2093 {
2094 return;
2095 }
2096
2097 // do not attempt to create storage for nonexistant data
2098 if (!isLevelComplete(0))
2099 {
2100 return;
2101 }
2102
2103 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2104
2105 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2106 ASSERT(mTexStorage);
2107
2108 // flush image data to the storage
2109 updateStorage();
2110}
2111
2112TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2113{
2114 GLsizei width = getBaseLevelWidth();
2115 GLsizei height = getBaseLevelHeight();
2116 GLsizei depth = getLayers(0);
2117
2118 ASSERT(width > 0 && height > 0 && depth > 0);
2119
2120 // use existing storage level count, when previously specified by TexStorage*D
2121 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2122
2123 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2124}
2125
2126void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2127{
2128 SafeDelete(mTexStorage);
2129 mTexStorage = newCompleteTexStorage;
2130 mDirtyImages = true;
2131
2132 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2133 ASSERT(!mTexStorage->isManaged());
2134}
2135
2136void TextureD3D_2DArray::updateStorage()
2137{
2138 ASSERT(mTexStorage != NULL);
2139 GLint storageLevels = mTexStorage->getLevelCount();
2140 for (int level = 0; level < storageLevels; level++)
2141 {
2142 if (isLevelComplete(level))
2143 {
2144 updateStorageLevel(level);
2145 }
2146 }
2147}
2148
2149bool TextureD3D_2DArray::ensureRenderTarget()
2150{
2151 initializeStorage(true);
2152
2153 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2154 {
2155 ASSERT(mTexStorage);
2156 if (!mTexStorage->isRenderTarget())
2157 {
2158 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2159
2160 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2161 {
2162 delete newRenderTargetStorage;
2163 return gl::error(GL_OUT_OF_MEMORY, false);
2164 }
2165
2166 setCompleteTexStorage(newRenderTargetStorage);
2167 }
2168 }
2169
2170 return (mTexStorage && mTexStorage->isRenderTarget());
2171}
2172
2173const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2174{
2175 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2176}
2177
2178TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2179{
2180 return mTexStorage;
2181}
2182
2183bool TextureD3D_2DArray::isValidLevel(int level) const
2184{
2185 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2186}
2187
2188bool TextureD3D_2DArray::isLevelComplete(int level) const
2189{
2190 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2191
2192 if (isImmutable())
2193 {
2194 return true;
2195 }
2196
2197 GLsizei width = getBaseLevelWidth();
2198 GLsizei height = getBaseLevelHeight();
2199 GLsizei layers = getLayers(0);
2200
2201 if (width <= 0 || height <= 0 || layers <= 0)
2202 {
2203 return false;
2204 }
2205
2206 if (level == 0)
2207 {
2208 return true;
2209 }
2210
2211 if (getInternalFormat(level) != getInternalFormat(0))
2212 {
2213 return false;
2214 }
2215
2216 if (getWidth(level) != std::max(1, width >> level))
2217 {
2218 return false;
2219 }
2220
2221 if (getHeight(level) != std::max(1, height >> level))
2222 {
2223 return false;
2224 }
2225
2226 if (getLayers(level) != layers)
2227 {
2228 return false;
2229 }
2230
2231 return true;
2232}
2233
2234void TextureD3D_2DArray::updateStorageLevel(int level)
2235{
2236 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2237 ASSERT(isLevelComplete(level));
2238
2239 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2240 {
2241 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2242 if (mImageArray[level][layer]->isDirty())
2243 {
2244 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2245 }
2246 }
2247}
2248
2249void TextureD3D_2DArray::deleteImages()
2250{
2251 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2252 {
2253 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2254 {
2255 delete mImageArray[level][layer];
2256 }
2257 delete[] mImageArray[level];
2258 mImageArray[level] = NULL;
2259 mLayerCounts[level] = 0;
2260 }
2261}
2262
2263void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2264{
2265 // If there currently is a corresponding storage texture image, it has these parameters
2266 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2267 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2268 const int storageDepth = getLayers(0);
2269 const GLenum storageFormat = getBaseLevelInternalFormat();
2270
2271 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2272 {
2273 delete mImageArray[level][layer];
2274 }
2275 delete[] mImageArray[level];
2276 mImageArray[level] = NULL;
2277 mLayerCounts[level] = depth;
2278
2279 if (depth > 0)
2280 {
2281 mImageArray[level] = new ImageD3D*[depth]();
2282
2283 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2284 {
2285 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2286 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2287 }
2288 }
2289
2290 if (mTexStorage)
2291 {
2292 const int storageLevels = mTexStorage->getLevelCount();
2293
2294 if ((level >= storageLevels && storageLevels != 0) ||
2295 width != storageWidth ||
2296 height != storageHeight ||
2297 depth != storageDepth ||
2298 internalformat != storageFormat) // Discard mismatched storage
2299 {
2300 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2301 {
2302 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2303 {
2304 mImageArray[level][layer]->markDirty();
2305 }
2306 }
2307
2308 delete mTexStorage;
2309 mTexStorage = NULL;
2310 mDirtyImages = true;
2311 }
2312 }
2313}
2314
2315void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2316{
2317 if (isValidLevel(level) && layerTarget < getLayers(level))
2318 {
2319 ImageD3D *image = mImageArray[level][layerTarget];
2320 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2321 {
2322 image->markClean();
2323 }
2324 }
2325}
2326
Brandon Jones78b1acd2014-07-15 15:33:07 -07002327}