blob: ae75cccf78330a693cd63936c890f8d4801c6dd0 [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);
Jamie Madillac7579c2014-09-17 16:59:33 -0400247 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400248 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 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400308 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
309
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700310 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400311 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700312 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
313
314 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
315 {
316 // Ensure we don't overwrite our newly initialized data
317 mImageArray[level]->markClean();
318
319 fastUnpacked = true;
320 }
321 }
322
323 if (!fastUnpacked)
324 {
325 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
326 }
327}
328
Brandon Jonescef06ff2014-08-05 13:27:48 -0700329void 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 -0700330{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700331 ASSERT(target == GL_TEXTURE_2D && depth == 1);
332
333 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
334 redefineImage(level, format, width, height);
335
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700336 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
337}
338
Brandon Jonescef06ff2014-08-05 13:27:48 -0700339void 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 -0700340{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700341 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
342
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700343 bool fastUnpacked = false;
344
Jamie Madillac7579c2014-09-17 16:59:33 -0400345 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700346 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
347 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400348 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700349 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
350
351 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
352 {
353 // Ensure we don't overwrite our newly initialized data
354 mImageArray[level]->markClean();
355
356 fastUnpacked = true;
357 }
358 }
359
Jamie Madillfeda4d22014-09-17 13:03:29 -0400360 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700361 {
362 commitRect(level, xoffset, yoffset, width, height);
363 }
364}
365
Brandon Jonescef06ff2014-08-05 13:27:48 -0700366void 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 -0700367{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700368 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
369
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
371 {
372 commitRect(level, xoffset, yoffset, width, height);
373 }
374}
375
Brandon Jonescef06ff2014-08-05 13:27:48 -0700376void 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 -0700377{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700378 ASSERT(target == GL_TEXTURE_2D);
379
380 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
381 redefineImage(level, sizedInternalFormat, width, height);
382
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700383 if (!mImageArray[level]->isRenderableFormat())
384 {
385 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
386 mDirtyImages = true;
387 }
388 else
389 {
390 ensureRenderTarget();
391 mImageArray[level]->markClean();
392
393 if (width != 0 && height != 0 && isValidLevel(level))
394 {
395 gl::Rectangle sourceRect;
396 sourceRect.x = x;
397 sourceRect.width = width;
398 sourceRect.y = y;
399 sourceRect.height = height;
400
401 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
402 }
403 }
404}
405
406void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
407{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700408 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
409
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700410 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
411 // the current level we're copying to is defined (with appropriate format, width & height)
412 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
413
414 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
415 {
416 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
417 mDirtyImages = true;
418 }
419 else
420 {
421 ensureRenderTarget();
422
423 if (isValidLevel(level))
424 {
425 updateStorageLevel(level);
426
427 gl::Rectangle sourceRect;
428 sourceRect.x = x;
429 sourceRect.width = width;
430 sourceRect.y = y;
431 sourceRect.height = height;
432
433 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400434 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435 xoffset, yoffset, mTexStorage, level);
436 }
437 }
438}
439
Brandon Jonescef06ff2014-08-05 13:27:48 -0700440void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700441{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700442 ASSERT(target == GL_TEXTURE_2D && depth == 1);
443
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700444 for (int level = 0; level < levels; level++)
445 {
446 GLsizei levelWidth = std::max(1, width >> level);
447 GLsizei levelHeight = std::max(1, height >> level);
448 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
449 }
450
451 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
452 {
453 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
454 }
455
456 mImmutable = true;
457
Brandon Jones78b1acd2014-07-15 15:33:07 -0700458 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700459}
460
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461void TextureD3D_2D::bindTexImage(egl::Surface *surface)
462{
463 GLenum internalformat = surface->getFormat();
464
465 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
466
467 if (mTexStorage)
468 {
469 SafeDelete(mTexStorage);
470 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700471 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700472
473 mDirtyImages = true;
474}
475
476void TextureD3D_2D::releaseTexImage()
477{
478 if (mTexStorage)
479 {
480 SafeDelete(mTexStorage);
481 }
482
483 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
484 {
485 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
486 }
487}
488
489void TextureD3D_2D::generateMipmaps()
490{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700491 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700492 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700493 for (int level = 1; level < levelCount; level++)
494 {
495 redefineImage(level, getBaseLevelInternalFormat(),
496 std::max(getBaseLevelWidth() >> level, 1),
497 std::max(getBaseLevelHeight() >> level, 1));
498 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700499
500 if (mTexStorage && mTexStorage->isRenderTarget())
501 {
502 for (int level = 1; level < levelCount; level++)
503 {
504 mTexStorage->generateMipmap(level);
505
506 mImageArray[level]->markClean();
507 }
508 }
509 else
510 {
511 for (int level = 1; level < levelCount; level++)
512 {
513 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
514 }
515 }
516}
517
Jamie Madillac7579c2014-09-17 16:59:33 -0400518unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519{
Jamie Madillac7579c2014-09-17 16:59:33 -0400520 ASSERT(!index.hasLayer());
521 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index.mipIndex) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522}
523
Jamie Madillac7579c2014-09-17 16:59:33 -0400524RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700525{
Jamie Madillac7579c2014-09-17 16:59:33 -0400526 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700527
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528 // ensure the underlying texture is created
529 if (!ensureRenderTarget())
530 {
531 return NULL;
532 }
533
Jamie Madillac7579c2014-09-17 16:59:33 -0400534 updateStorageLevel(index.mipIndex);
535 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536}
537
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538bool TextureD3D_2D::isValidLevel(int level) const
539{
540 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
541}
542
543bool TextureD3D_2D::isLevelComplete(int level) const
544{
545 if (isImmutable())
546 {
547 return true;
548 }
549
Brandon Jones78b1acd2014-07-15 15:33:07 -0700550 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551
552 GLsizei width = baseImage->getWidth();
553 GLsizei height = baseImage->getHeight();
554
555 if (width <= 0 || height <= 0)
556 {
557 return false;
558 }
559
560 // The base image level is complete if the width and height are positive
561 if (level == 0)
562 {
563 return true;
564 }
565
566 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700567 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700568
569 if (image->getInternalFormat() != baseImage->getInternalFormat())
570 {
571 return false;
572 }
573
574 if (image->getWidth() != std::max(1, width >> level))
575 {
576 return false;
577 }
578
579 if (image->getHeight() != std::max(1, height >> level))
580 {
581 return false;
582 }
583
584 return true;
585}
586
587// Constructs a native texture resource from the texture images
588void TextureD3D_2D::initializeStorage(bool renderTarget)
589{
590 // Only initialize the first time this texture is used as a render target or shader resource
591 if (mTexStorage)
592 {
593 return;
594 }
595
596 // do not attempt to create storage for nonexistant data
597 if (!isLevelComplete(0))
598 {
599 return;
600 }
601
602 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
603
604 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
605 ASSERT(mTexStorage);
606
607 // flush image data to the storage
608 updateStorage();
609}
610
Brandon Jones78b1acd2014-07-15 15:33:07 -0700611TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700612{
613 GLsizei width = getBaseLevelWidth();
614 GLsizei height = getBaseLevelHeight();
615
616 ASSERT(width > 0 && height > 0);
617
618 // use existing storage level count, when previously specified by TexStorage*D
619 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
620
Brandon Jones78b1acd2014-07-15 15:33:07 -0700621 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622}
623
624void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
625{
626 SafeDelete(mTexStorage);
627 mTexStorage = newCompleteTexStorage;
628
629 if (mTexStorage && mTexStorage->isManaged())
630 {
631 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
632 {
633 mImageArray[level]->setManagedSurface(mTexStorage, level);
634 }
635 }
636
637 mDirtyImages = true;
638}
639
640void TextureD3D_2D::updateStorage()
641{
642 ASSERT(mTexStorage != NULL);
643 GLint storageLevels = mTexStorage->getLevelCount();
644 for (int level = 0; level < storageLevels; level++)
645 {
646 if (mImageArray[level]->isDirty() && isLevelComplete(level))
647 {
648 updateStorageLevel(level);
649 }
650 }
651}
652
653bool TextureD3D_2D::ensureRenderTarget()
654{
655 initializeStorage(true);
656
657 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
658 {
659 ASSERT(mTexStorage);
660 if (!mTexStorage->isRenderTarget())
661 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700662 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663
664 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
665 {
666 delete newRenderTargetStorage;
667 return gl::error(GL_OUT_OF_MEMORY, false);
668 }
669
670 setCompleteTexStorage(newRenderTargetStorage);
671 }
672 }
673
674 return (mTexStorage && mTexStorage->isRenderTarget());
675}
676
677TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
678{
679 return mTexStorage;
680}
681
682const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
683{
684 return mImageArray[0];
685}
686
687void TextureD3D_2D::updateStorageLevel(int level)
688{
689 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
690 ASSERT(isLevelComplete(level));
691
692 if (mImageArray[level]->isDirty())
693 {
694 commitRect(level, 0, 0, getWidth(level), getHeight(level));
695 }
696}
697
698void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
699{
700 // If there currently is a corresponding storage texture image, it has these parameters
701 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
702 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
703 const GLenum storageFormat = getBaseLevelInternalFormat();
704
705 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
706
707 if (mTexStorage)
708 {
709 const int storageLevels = mTexStorage->getLevelCount();
710
711 if ((level >= storageLevels && storageLevels != 0) ||
712 width != storageWidth ||
713 height != storageHeight ||
714 internalformat != storageFormat) // Discard mismatched storage
715 {
716 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
717 {
718 mImageArray[i]->markDirty();
719 }
720
721 SafeDelete(mTexStorage);
722 mDirtyImages = true;
723 }
724 }
725}
726
727void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
728{
729 if (isValidLevel(level))
730 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700731 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700732 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
733 {
734 image->markClean();
735 }
736 }
737}
738
Brandon Jones0511e802014-07-14 16:27:26 -0700739
Brandon Jones78b1acd2014-07-15 15:33:07 -0700740TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700741 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700742 mTexStorage(NULL)
743{
744 for (int i = 0; i < 6; i++)
745 {
746 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
747 {
748 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
749 }
750 }
751}
752
753TextureD3D_Cube::~TextureD3D_Cube()
754{
Austin Kinross69822602014-08-12 15:51:37 -0700755 // Delete the Images before the TextureStorage.
756 // Images might be relying on the TextureStorage for some of their data.
757 // 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 -0700758 for (int i = 0; i < 6; i++)
759 {
760 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
761 {
762 SafeDelete(mImageArray[i][j]);
763 }
764 }
Austin Kinross69822602014-08-12 15:51:37 -0700765
766 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700767}
768
Brandon Jonescef06ff2014-08-05 13:27:48 -0700769Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700770{
771 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700772 ASSERT(layer < 6);
773 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700774}
775
Jamie Madillfeda4d22014-09-17 13:03:29 -0400776Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
777{
778 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
779 ASSERT(index.layerIndex < 6);
780 return mImageArray[index.layerIndex][index.mipIndex];
781}
782
Brandon Jonescef06ff2014-08-05 13:27:48 -0700783GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700784{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700785 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
786 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700787}
788
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700790{
791 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700793 else
794 return GL_NONE;
795}
796
Brandon Jonescef06ff2014-08-05 13:27:48 -0700797bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700798{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700799 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700800}
801
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802void 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 -0700803{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700804 ASSERT(depth == 1);
805
806 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400807 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700808
809 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
810
811 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
812}
813
Brandon Jonescef06ff2014-08-05 13:27:48 -0700814void 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 -0700815{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700816 ASSERT(depth == 1);
817
Brandon Jones0511e802014-07-14 16:27:26 -0700818 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700819 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
820
Brandon Jones0511e802014-07-14 16:27:26 -0700821 redefineImage(faceIndex, level, format, width, height);
822
823 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
824}
825
Brandon Jonescef06ff2014-08-05 13:27:48 -0700826void 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 -0700827{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700828 ASSERT(depth == 1 && zoffset == 0);
829
830 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
831
Jamie Madillfeda4d22014-09-17 13:03:29 -0400832 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
833 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700834 {
835 commitRect(faceIndex, level, xoffset, yoffset, width, height);
836 }
837}
838
Brandon Jonescef06ff2014-08-05 13:27:48 -0700839void 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 -0700840{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700841 ASSERT(depth == 1 && zoffset == 0);
842
843 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
844
Brandon Jones0511e802014-07-14 16:27:26 -0700845 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
846 {
847 commitRect(faceIndex, level, xoffset, yoffset, width, height);
848 }
849}
850
851void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
852{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700853 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400854 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
855
Brandon Jones0511e802014-07-14 16:27:26 -0700856 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
857
858 if (!mImageArray[faceIndex][level]->isRenderableFormat())
859 {
860 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
861 mDirtyImages = true;
862 }
863 else
864 {
865 ensureRenderTarget();
866 mImageArray[faceIndex][level]->markClean();
867
868 ASSERT(width == height);
869
870 if (width > 0 && isValidFaceLevel(faceIndex, level))
871 {
872 gl::Rectangle sourceRect;
873 sourceRect.x = x;
874 sourceRect.width = width;
875 sourceRect.y = y;
876 sourceRect.height = height;
877
878 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
879 }
880 }
881}
882
883void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
884{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700885 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700886
887 // We can only make our texture storage to a render target if the level we're copying *to* is complete
888 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
889 // rely on the "getBaseLevel*" methods reliably otherwise.
890 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
891
892 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
893 {
894 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
895 mDirtyImages = true;
896 }
897 else
898 {
899 ensureRenderTarget();
900
901 if (isValidFaceLevel(faceIndex, level))
902 {
903 updateStorageFaceLevel(faceIndex, level);
904
905 gl::Rectangle sourceRect;
906 sourceRect.x = x;
907 sourceRect.width = width;
908 sourceRect.y = y;
909 sourceRect.height = height;
910
Geoff Lang5d601382014-07-22 15:14:06 -0400911 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700912 xoffset, yoffset, mTexStorage, target, level);
913 }
914 }
915}
916
Brandon Jonescef06ff2014-08-05 13:27:48 -0700917void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700918{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700919 ASSERT(width == height);
920 ASSERT(depth == 1);
921
Brandon Jones0511e802014-07-14 16:27:26 -0700922 for (int level = 0; level < levels; level++)
923 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700925 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
926 {
927 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
928 }
929 }
930
931 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
932 {
933 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
934 {
935 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
936 }
937 }
938
939 mImmutable = true;
940
Brandon Jonescef06ff2014-08-05 13:27:48 -0700941 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700942}
943
Brandon Jones0511e802014-07-14 16:27:26 -0700944// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
945bool TextureD3D_Cube::isCubeComplete() const
946{
947 int baseWidth = getBaseLevelWidth();
948 int baseHeight = getBaseLevelHeight();
949 GLenum baseFormat = getBaseLevelInternalFormat();
950
951 if (baseWidth <= 0 || baseWidth != baseHeight)
952 {
953 return false;
954 }
955
956 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
957 {
958 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
959
960 if (faceBaseImage.getWidth() != baseWidth ||
961 faceBaseImage.getHeight() != baseHeight ||
962 faceBaseImage.getInternalFormat() != baseFormat )
963 {
964 return false;
965 }
966 }
967
968 return true;
969}
970
Brandon Jones6053a522014-07-25 16:22:09 -0700971void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
972{
973 UNREACHABLE();
974}
975
976void TextureD3D_Cube::releaseTexImage()
977{
978 UNREACHABLE();
979}
980
981
Brandon Jones0511e802014-07-14 16:27:26 -0700982void TextureD3D_Cube::generateMipmaps()
983{
984 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
985 int levelCount = mipLevels();
986 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
987 {
988 for (int level = 1; level < levelCount; level++)
989 {
990 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
991 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
992 }
993 }
994
995 if (mTexStorage && mTexStorage->isRenderTarget())
996 {
997 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
998 {
999 for (int level = 1; level < levelCount; level++)
1000 {
1001 mTexStorage->generateMipmap(faceIndex, level);
1002
1003 mImageArray[faceIndex][level]->markClean();
1004 }
1005 }
1006 }
1007 else
1008 {
1009 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1010 {
1011 for (int level = 1; level < levelCount; level++)
1012 {
1013 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1014 }
1015 }
1016 }
1017}
1018
Jamie Madillac7579c2014-09-17 16:59:33 -04001019unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001020{
Jamie Madillac7579c2014-09-17 16:59:33 -04001021 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index.type, index.mipIndex) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001022}
1023
Jamie Madillac7579c2014-09-17 16:59:33 -04001024RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001025{
Jamie Madillac7579c2014-09-17 16:59:33 -04001026 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001027
1028 // ensure the underlying texture is created
1029 if (!ensureRenderTarget())
1030 {
1031 return NULL;
1032 }
1033
Jamie Madillac7579c2014-09-17 16:59:33 -04001034 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1035 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001036}
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);
Jamie Madillac7579c2014-09-17 16:59:33 -04001277 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001278 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
Jamie Madillac7579c2014-09-17 16:59:33 -04001338 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1339 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001340 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1341
1342 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1343 {
1344 // Ensure we don't overwrite our newly initialized data
1345 mImageArray[level]->markClean();
1346
1347 fastUnpacked = true;
1348 }
1349 }
1350
1351 if (!fastUnpacked)
1352 {
1353 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1354 }
1355}
1356
Brandon Jonescef06ff2014-08-05 13:27:48 -07001357void 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 -07001358{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001359 ASSERT(target == GL_TEXTURE_3D);
1360
Brandon Jones78b1acd2014-07-15 15:33:07 -07001361 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1362 redefineImage(level, format, width, height, depth);
1363
1364 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1365}
1366
Brandon Jonescef06ff2014-08-05 13:27:48 -07001367void 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 -07001368{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001369 ASSERT(target == GL_TEXTURE_3D);
1370
Brandon Jones78b1acd2014-07-15 15:33:07 -07001371 bool fastUnpacked = false;
1372
Jamie Madillac7579c2014-09-17 16:59:33 -04001373 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1374
Brandon Jones78b1acd2014-07-15 15:33:07 -07001375 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1376 if (isFastUnpackable(unpack, getInternalFormat(level)))
1377 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001378 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001379 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1380
1381 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1382 {
1383 // Ensure we don't overwrite our newly initialized data
1384 mImageArray[level]->markClean();
1385
1386 fastUnpacked = true;
1387 }
1388 }
1389
Jamie Madillfeda4d22014-09-17 13:03:29 -04001390 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001391 {
1392 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1393 }
1394}
1395
Brandon Jonescef06ff2014-08-05 13:27:48 -07001396void 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 -07001397{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001398 ASSERT(target == GL_TEXTURE_3D);
1399
Brandon Jones78b1acd2014-07-15 15:33:07 -07001400 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1401 {
1402 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1403 }
1404}
1405
Brandon Jonescef06ff2014-08-05 13:27:48 -07001406void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1407{
1408 UNIMPLEMENTED();
1409}
1410
Brandon Jones78b1acd2014-07-15 15:33:07 -07001411void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1412{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001413 ASSERT(target == GL_TEXTURE_3D);
1414
Brandon Jones78b1acd2014-07-15 15:33:07 -07001415 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1416 // the current level we're copying to is defined (with appropriate format, width & height)
1417 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1418
1419 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1420 {
1421 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1422 mDirtyImages = true;
1423 }
1424 else
1425 {
1426 ensureRenderTarget();
1427
1428 if (isValidLevel(level))
1429 {
1430 updateStorageLevel(level);
1431
1432 gl::Rectangle sourceRect;
1433 sourceRect.x = x;
1434 sourceRect.width = width;
1435 sourceRect.y = y;
1436 sourceRect.height = height;
1437
1438 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001439 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001440 xoffset, yoffset, zoffset, mTexStorage, level);
1441 }
1442 }
1443}
1444
Brandon Jonescef06ff2014-08-05 13:27:48 -07001445void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001446{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001447 ASSERT(target == GL_TEXTURE_3D);
1448
Brandon Jones78b1acd2014-07-15 15:33:07 -07001449 for (int level = 0; level < levels; level++)
1450 {
1451 GLsizei levelWidth = std::max(1, width >> level);
1452 GLsizei levelHeight = std::max(1, height >> level);
1453 GLsizei levelDepth = std::max(1, depth >> level);
1454 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1455 }
1456
1457 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1458 {
1459 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1460 }
1461
1462 mImmutable = true;
1463
1464 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1465}
1466
Brandon Jones6053a522014-07-25 16:22:09 -07001467void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001468{
Brandon Jones6053a522014-07-25 16:22:09 -07001469 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001470}
1471
Brandon Jones6053a522014-07-25 16:22:09 -07001472void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001473{
Brandon Jones6053a522014-07-25 16:22:09 -07001474 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475}
1476
Brandon Jones6053a522014-07-25 16:22:09 -07001477
Brandon Jones78b1acd2014-07-15 15:33:07 -07001478void TextureD3D_3D::generateMipmaps()
1479{
1480 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1481 int levelCount = mipLevels();
1482 for (int level = 1; level < levelCount; level++)
1483 {
1484 redefineImage(level, getBaseLevelInternalFormat(),
1485 std::max(getBaseLevelWidth() >> level, 1),
1486 std::max(getBaseLevelHeight() >> level, 1),
1487 std::max(getBaseLevelDepth() >> level, 1));
1488 }
1489
1490 if (mTexStorage && mTexStorage->isRenderTarget())
1491 {
1492 for (int level = 1; level < levelCount; level++)
1493 {
1494 mTexStorage->generateMipmap(level);
1495
1496 mImageArray[level]->markClean();
1497 }
1498 }
1499 else
1500 {
1501 for (int level = 1; level < levelCount; level++)
1502 {
1503 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1504 }
1505 }
1506}
1507
Jamie Madillac7579c2014-09-17 16:59:33 -04001508unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001509{
Jamie Madillac7579c2014-09-17 16:59:33 -04001510 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index.mipIndex, index.layerIndex) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511}
1512
Jamie Madillac7579c2014-09-17 16:59:33 -04001513RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001514{
1515 // ensure the underlying texture is created
1516 if (!ensureRenderTarget())
1517 {
1518 return NULL;
1519 }
1520
Jamie Madillac7579c2014-09-17 16:59:33 -04001521 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001522 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001523 updateStorage();
1524 }
1525 else
1526 {
1527 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001528 }
1529
Jamie Madillac7579c2014-09-17 16:59:33 -04001530 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531}
1532
1533void TextureD3D_3D::initializeStorage(bool renderTarget)
1534{
1535 // Only initialize the first time this texture is used as a render target or shader resource
1536 if (mTexStorage)
1537 {
1538 return;
1539 }
1540
1541 // do not attempt to create storage for nonexistant data
1542 if (!isLevelComplete(0))
1543 {
1544 return;
1545 }
1546
1547 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1548
1549 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1550 ASSERT(mTexStorage);
1551
1552 // flush image data to the storage
1553 updateStorage();
1554}
1555
1556TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1557{
1558 GLsizei width = getBaseLevelWidth();
1559 GLsizei height = getBaseLevelHeight();
1560 GLsizei depth = getBaseLevelDepth();
1561
1562 ASSERT(width > 0 && height > 0 && depth > 0);
1563
1564 // use existing storage level count, when previously specified by TexStorage*D
1565 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1566
1567 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1568}
1569
1570void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1571{
1572 SafeDelete(mTexStorage);
1573 mTexStorage = newCompleteTexStorage;
1574 mDirtyImages = true;
1575
1576 // We do not support managed 3D storage, as that is D3D9/ES2-only
1577 ASSERT(!mTexStorage->isManaged());
1578}
1579
1580void TextureD3D_3D::updateStorage()
1581{
1582 ASSERT(mTexStorage != NULL);
1583 GLint storageLevels = mTexStorage->getLevelCount();
1584 for (int level = 0; level < storageLevels; level++)
1585 {
1586 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1587 {
1588 updateStorageLevel(level);
1589 }
1590 }
1591}
1592
1593bool TextureD3D_3D::ensureRenderTarget()
1594{
1595 initializeStorage(true);
1596
1597 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1598 {
1599 ASSERT(mTexStorage);
1600 if (!mTexStorage->isRenderTarget())
1601 {
1602 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1603
1604 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1605 {
1606 delete newRenderTargetStorage;
1607 return gl::error(GL_OUT_OF_MEMORY, false);
1608 }
1609
1610 setCompleteTexStorage(newRenderTargetStorage);
1611 }
1612 }
1613
1614 return (mTexStorage && mTexStorage->isRenderTarget());
1615}
1616
1617TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1618{
1619 return mTexStorage;
1620}
1621
1622const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1623{
1624 return mImageArray[0];
1625}
1626
1627bool TextureD3D_3D::isValidLevel(int level) const
1628{
1629 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1630}
1631
1632bool TextureD3D_3D::isLevelComplete(int level) const
1633{
1634 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1635
1636 if (isImmutable())
1637 {
1638 return true;
1639 }
1640
1641 GLsizei width = getBaseLevelWidth();
1642 GLsizei height = getBaseLevelHeight();
1643 GLsizei depth = getBaseLevelDepth();
1644
1645 if (width <= 0 || height <= 0 || depth <= 0)
1646 {
1647 return false;
1648 }
1649
1650 if (level == 0)
1651 {
1652 return true;
1653 }
1654
1655 ImageD3D *levelImage = mImageArray[level];
1656
1657 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1658 {
1659 return false;
1660 }
1661
1662 if (levelImage->getWidth() != std::max(1, width >> level))
1663 {
1664 return false;
1665 }
1666
1667 if (levelImage->getHeight() != std::max(1, height >> level))
1668 {
1669 return false;
1670 }
1671
1672 if (levelImage->getDepth() != std::max(1, depth >> level))
1673 {
1674 return false;
1675 }
1676
1677 return true;
1678}
1679
1680void TextureD3D_3D::updateStorageLevel(int level)
1681{
1682 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1683 ASSERT(isLevelComplete(level));
1684
1685 if (mImageArray[level]->isDirty())
1686 {
1687 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1688 }
1689}
1690
1691void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1692{
1693 // If there currently is a corresponding storage texture image, it has these parameters
1694 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1695 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1696 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1697 const GLenum storageFormat = getBaseLevelInternalFormat();
1698
1699 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1700
1701 if (mTexStorage)
1702 {
1703 const int storageLevels = mTexStorage->getLevelCount();
1704
1705 if ((level >= storageLevels && storageLevels != 0) ||
1706 width != storageWidth ||
1707 height != storageHeight ||
1708 depth != storageDepth ||
1709 internalformat != storageFormat) // Discard mismatched storage
1710 {
1711 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1712 {
1713 mImageArray[i]->markDirty();
1714 }
1715
1716 SafeDelete(mTexStorage);
1717 mDirtyImages = true;
1718 }
1719 }
1720}
1721
1722void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1723{
1724 if (isValidLevel(level))
1725 {
1726 ImageD3D *image = mImageArray[level];
1727 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1728 {
1729 image->markClean();
1730 }
1731 }
1732}
1733
Brandon Jones142ec422014-07-16 10:31:30 -07001734
1735TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001736 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001737 mTexStorage(NULL)
1738{
1739 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1740 {
1741 mLayerCounts[level] = 0;
1742 mImageArray[level] = NULL;
1743 }
1744}
1745
1746TextureD3D_2DArray::~TextureD3D_2DArray()
1747{
Austin Kinross69822602014-08-12 15:51:37 -07001748 // Delete the Images before the TextureStorage.
1749 // Images might be relying on the TextureStorage for some of their data.
1750 // 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 -07001751 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001752 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001753}
1754
Brandon Jones142ec422014-07-16 10:31:30 -07001755Image *TextureD3D_2DArray::getImage(int level, int layer) const
1756{
1757 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1758 ASSERT(layer < mLayerCounts[level]);
1759 return mImageArray[level][layer];
1760}
1761
Jamie Madillfeda4d22014-09-17 13:03:29 -04001762Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1763{
1764 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1765 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1766 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1767 return mImageArray[index.mipIndex][index.layerIndex];
1768}
1769
Brandon Jones142ec422014-07-16 10:31:30 -07001770GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1771{
1772 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1773 return mLayerCounts[level];
1774}
1775
Brandon Jones142ec422014-07-16 10:31:30 -07001776GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1777{
1778 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1779}
1780
1781GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1782{
1783 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1784}
1785
1786GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1787{
1788 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1789}
1790
1791GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1792{
1793 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1794}
1795
1796bool TextureD3D_2DArray::isDepth(GLint level) const
1797{
Geoff Lang5d601382014-07-22 15:14:06 -04001798 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001799}
1800
Brandon Jonescef06ff2014-08-05 13:27:48 -07001801void 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 -07001802{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001803 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1804
Geoff Lang5d601382014-07-22 15:14:06 -04001805 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1806
Brandon Jones142ec422014-07-16 10:31:30 -07001807 redefineImage(level, sizedInternalFormat, width, height, depth);
1808
Geoff Lang5d601382014-07-22 15:14:06 -04001809 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1810 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001811
1812 for (int i = 0; i < depth; i++)
1813 {
1814 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1815 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1816 }
1817}
1818
Brandon Jonescef06ff2014-08-05 13:27:48 -07001819void 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 -07001820{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001821 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1822
Brandon Jones142ec422014-07-16 10:31:30 -07001823 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1824 redefineImage(level, format, width, height, depth);
1825
Geoff Lang5d601382014-07-22 15:14:06 -04001826 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1827 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001828
1829 for (int i = 0; i < depth; i++)
1830 {
1831 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1832 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1833 }
1834}
1835
Brandon Jonescef06ff2014-08-05 13:27:48 -07001836void 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 -07001837{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001838 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1839
Geoff Lang5d601382014-07-22 15:14:06 -04001840 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1841 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001842
1843 for (int i = 0; i < depth; i++)
1844 {
1845 int layer = zoffset + i;
1846 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1847
Jamie Madillfeda4d22014-09-17 13:03:29 -04001848 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1849 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001850 {
1851 commitRect(level, xoffset, yoffset, layer, width, height);
1852 }
1853 }
1854}
1855
Brandon Jonescef06ff2014-08-05 13:27:48 -07001856void 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 -07001857{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001858 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1859
Geoff Lang5d601382014-07-22 15:14:06 -04001860 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1861 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001862
1863 for (int i = 0; i < depth; i++)
1864 {
1865 int layer = zoffset + i;
1866 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1867
1868 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1869 {
1870 commitRect(level, xoffset, yoffset, layer, width, height);
1871 }
1872 }
1873}
1874
Brandon Jonescef06ff2014-08-05 13:27:48 -07001875void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1876{
1877 UNIMPLEMENTED();
1878}
1879
Brandon Jones142ec422014-07-16 10:31:30 -07001880void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1881{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001882 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1883
Brandon Jones142ec422014-07-16 10:31:30 -07001884 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1885 // the current level we're copying to is defined (with appropriate format, width & height)
1886 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1887
1888 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1889 {
1890 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1891 mDirtyImages = true;
1892 }
1893 else
1894 {
1895 ensureRenderTarget();
1896
1897 if (isValidLevel(level))
1898 {
1899 updateStorageLevel(level);
1900
1901 gl::Rectangle sourceRect;
1902 sourceRect.x = x;
1903 sourceRect.width = width;
1904 sourceRect.y = y;
1905 sourceRect.height = height;
1906
Geoff Lang5d601382014-07-22 15:14:06 -04001907 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001908 xoffset, yoffset, zoffset, mTexStorage, level);
1909 }
1910 }
1911}
1912
Brandon Jonescef06ff2014-08-05 13:27:48 -07001913void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001914{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001915 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1916
Brandon Jones142ec422014-07-16 10:31:30 -07001917 deleteImages();
1918
1919 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1920 {
1921 GLsizei levelWidth = std::max(1, width >> level);
1922 GLsizei levelHeight = std::max(1, height >> level);
1923
1924 mLayerCounts[level] = (level < levels ? depth : 0);
1925
1926 if (mLayerCounts[level] > 0)
1927 {
1928 // Create new images for this level
1929 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1930
1931 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1932 {
1933 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1934 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1935 levelHeight, 1, true);
1936 }
1937 }
1938 }
1939
1940 mImmutable = true;
1941 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1942}
1943
Brandon Jones6053a522014-07-25 16:22:09 -07001944void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001945{
Brandon Jones6053a522014-07-25 16:22:09 -07001946 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001947}
1948
Brandon Jones6053a522014-07-25 16:22:09 -07001949void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001950{
Brandon Jones6053a522014-07-25 16:22:09 -07001951 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001952}
1953
Brandon Jones6053a522014-07-25 16:22:09 -07001954
Brandon Jones142ec422014-07-16 10:31:30 -07001955void TextureD3D_2DArray::generateMipmaps()
1956{
1957 int baseWidth = getBaseLevelWidth();
1958 int baseHeight = getBaseLevelHeight();
1959 int baseDepth = getBaseLevelDepth();
1960 GLenum baseFormat = getBaseLevelInternalFormat();
1961
1962 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1963 int levelCount = mipLevels();
1964 for (int level = 1; level < levelCount; level++)
1965 {
1966 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1967 }
1968
1969 if (mTexStorage && mTexStorage->isRenderTarget())
1970 {
1971 for (int level = 1; level < levelCount; level++)
1972 {
1973 mTexStorage->generateMipmap(level);
1974
1975 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1976 {
1977 mImageArray[level][layer]->markClean();
1978 }
1979 }
1980 }
1981 else
1982 {
1983 for (int level = 1; level < levelCount; level++)
1984 {
1985 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1986 {
1987 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
1988 }
1989 }
1990 }
1991}
1992
Jamie Madillac7579c2014-09-17 16:59:33 -04001993unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07001994{
Jamie Madillac7579c2014-09-17 16:59:33 -04001995 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index.mipIndex, index.layerIndex) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07001996}
1997
Jamie Madillac7579c2014-09-17 16:59:33 -04001998RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07001999{
2000 // ensure the underlying texture is created
2001 if (!ensureRenderTarget())
2002 {
2003 return NULL;
2004 }
2005
Jamie Madillac7579c2014-09-17 16:59:33 -04002006 updateStorageLevel(index.mipIndex);
2007 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002008}
2009
2010void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2011{
2012 // Only initialize the first time this texture is used as a render target or shader resource
2013 if (mTexStorage)
2014 {
2015 return;
2016 }
2017
2018 // do not attempt to create storage for nonexistant data
2019 if (!isLevelComplete(0))
2020 {
2021 return;
2022 }
2023
2024 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2025
2026 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2027 ASSERT(mTexStorage);
2028
2029 // flush image data to the storage
2030 updateStorage();
2031}
2032
2033TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2034{
2035 GLsizei width = getBaseLevelWidth();
2036 GLsizei height = getBaseLevelHeight();
2037 GLsizei depth = getLayers(0);
2038
2039 ASSERT(width > 0 && height > 0 && depth > 0);
2040
2041 // use existing storage level count, when previously specified by TexStorage*D
2042 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2043
2044 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2045}
2046
2047void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2048{
2049 SafeDelete(mTexStorage);
2050 mTexStorage = newCompleteTexStorage;
2051 mDirtyImages = true;
2052
2053 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2054 ASSERT(!mTexStorage->isManaged());
2055}
2056
2057void TextureD3D_2DArray::updateStorage()
2058{
2059 ASSERT(mTexStorage != NULL);
2060 GLint storageLevels = mTexStorage->getLevelCount();
2061 for (int level = 0; level < storageLevels; level++)
2062 {
2063 if (isLevelComplete(level))
2064 {
2065 updateStorageLevel(level);
2066 }
2067 }
2068}
2069
2070bool TextureD3D_2DArray::ensureRenderTarget()
2071{
2072 initializeStorage(true);
2073
2074 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2075 {
2076 ASSERT(mTexStorage);
2077 if (!mTexStorage->isRenderTarget())
2078 {
2079 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2080
2081 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2082 {
2083 delete newRenderTargetStorage;
2084 return gl::error(GL_OUT_OF_MEMORY, false);
2085 }
2086
2087 setCompleteTexStorage(newRenderTargetStorage);
2088 }
2089 }
2090
2091 return (mTexStorage && mTexStorage->isRenderTarget());
2092}
2093
2094const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2095{
2096 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2097}
2098
2099TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2100{
2101 return mTexStorage;
2102}
2103
2104bool TextureD3D_2DArray::isValidLevel(int level) const
2105{
2106 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2107}
2108
2109bool TextureD3D_2DArray::isLevelComplete(int level) const
2110{
2111 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2112
2113 if (isImmutable())
2114 {
2115 return true;
2116 }
2117
2118 GLsizei width = getBaseLevelWidth();
2119 GLsizei height = getBaseLevelHeight();
2120 GLsizei layers = getLayers(0);
2121
2122 if (width <= 0 || height <= 0 || layers <= 0)
2123 {
2124 return false;
2125 }
2126
2127 if (level == 0)
2128 {
2129 return true;
2130 }
2131
2132 if (getInternalFormat(level) != getInternalFormat(0))
2133 {
2134 return false;
2135 }
2136
2137 if (getWidth(level) != std::max(1, width >> level))
2138 {
2139 return false;
2140 }
2141
2142 if (getHeight(level) != std::max(1, height >> level))
2143 {
2144 return false;
2145 }
2146
2147 if (getLayers(level) != layers)
2148 {
2149 return false;
2150 }
2151
2152 return true;
2153}
2154
2155void TextureD3D_2DArray::updateStorageLevel(int level)
2156{
2157 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2158 ASSERT(isLevelComplete(level));
2159
2160 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2161 {
2162 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2163 if (mImageArray[level][layer]->isDirty())
2164 {
2165 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2166 }
2167 }
2168}
2169
2170void TextureD3D_2DArray::deleteImages()
2171{
2172 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2173 {
2174 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2175 {
2176 delete mImageArray[level][layer];
2177 }
2178 delete[] mImageArray[level];
2179 mImageArray[level] = NULL;
2180 mLayerCounts[level] = 0;
2181 }
2182}
2183
2184void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2185{
2186 // If there currently is a corresponding storage texture image, it has these parameters
2187 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2188 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2189 const int storageDepth = getLayers(0);
2190 const GLenum storageFormat = getBaseLevelInternalFormat();
2191
2192 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2193 {
2194 delete mImageArray[level][layer];
2195 }
2196 delete[] mImageArray[level];
2197 mImageArray[level] = NULL;
2198 mLayerCounts[level] = depth;
2199
2200 if (depth > 0)
2201 {
2202 mImageArray[level] = new ImageD3D*[depth]();
2203
2204 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2205 {
2206 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2207 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2208 }
2209 }
2210
2211 if (mTexStorage)
2212 {
2213 const int storageLevels = mTexStorage->getLevelCount();
2214
2215 if ((level >= storageLevels && storageLevels != 0) ||
2216 width != storageWidth ||
2217 height != storageHeight ||
2218 depth != storageDepth ||
2219 internalformat != storageFormat) // Discard mismatched storage
2220 {
2221 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2222 {
2223 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2224 {
2225 mImageArray[level][layer]->markDirty();
2226 }
2227 }
2228
2229 delete mTexStorage;
2230 mTexStorage = NULL;
2231 mDirtyImages = true;
2232 }
2233 }
2234}
2235
2236void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2237{
2238 if (isValidLevel(level) && layerTarget < getLayers(level))
2239 {
2240 ImageD3D *image = mImageArray[level][layerTarget];
2241 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2242 {
2243 image->markClean();
2244 }
2245 }
2246}
2247
Brandon Jones78b1acd2014-07-15 15:33:07 -07002248}