blob: 7bb6947374090d4eb1101b5936bc317f257248d7 [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
Jamie Madill2f06dbf2014-09-18 15:08:50 -040052TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070053{
54 // ensure the underlying texture is created
55 initializeStorage(false);
56
Jamie Madill2f06dbf2014-09-18 15:08:50 -040057 TextureStorage *storage = getBaseLevelStorage();
Brandon Jones6053a522014-07-25 16:22:09 -070058 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
Jamie Madill856d9d42014-09-18 15:08:49 -0400401 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700402 }
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
Jamie Madill856d9d42014-09-18 15:08:49 -0400433 mRenderer->copyImage2D(source, sourceRect,
434 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
435 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700436 }
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
Jamie Madillc4833262014-09-18 16:18:26 -0400458 bool renderTarget = IsRenderTargetUsage(mUsage);
459 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400460 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461}
462
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700463void TextureD3D_2D::bindTexImage(egl::Surface *surface)
464{
465 GLenum internalformat = surface->getFormat();
466
467 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
468
469 if (mTexStorage)
470 {
471 SafeDelete(mTexStorage);
472 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400473
474 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700475
476 mDirtyImages = true;
477}
478
479void TextureD3D_2D::releaseTexImage()
480{
481 if (mTexStorage)
482 {
483 SafeDelete(mTexStorage);
484 }
485
486 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
487 {
488 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
489 }
490}
491
492void TextureD3D_2D::generateMipmaps()
493{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700494 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700495 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700496 for (int level = 1; level < levelCount; level++)
497 {
498 redefineImage(level, getBaseLevelInternalFormat(),
499 std::max(getBaseLevelWidth() >> level, 1),
500 std::max(getBaseLevelHeight() >> level, 1));
501 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700502
503 if (mTexStorage && mTexStorage->isRenderTarget())
504 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400505 mTexStorage->generateMipmaps();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700506 for (int level = 1; level < levelCount; level++)
507 {
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700508 mImageArray[level]->markClean();
509 }
510 }
511 else
512 {
513 for (int level = 1; level < levelCount; level++)
514 {
515 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
516 }
517 }
518}
519
Jamie Madillac7579c2014-09-17 16:59:33 -0400520unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700521{
Jamie Madillac7579c2014-09-17 16:59:33 -0400522 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400523 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700524}
525
Jamie Madillac7579c2014-09-17 16:59:33 -0400526RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700527{
Jamie Madillac7579c2014-09-17 16:59:33 -0400528 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700529
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700530 // ensure the underlying texture is created
531 if (!ensureRenderTarget())
532 {
533 return NULL;
534 }
535
Jamie Madillac7579c2014-09-17 16:59:33 -0400536 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400537 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538}
539
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540bool TextureD3D_2D::isValidLevel(int level) const
541{
542 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
543}
544
545bool TextureD3D_2D::isLevelComplete(int level) const
546{
547 if (isImmutable())
548 {
549 return true;
550 }
551
Brandon Jones78b1acd2014-07-15 15:33:07 -0700552 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700553
554 GLsizei width = baseImage->getWidth();
555 GLsizei height = baseImage->getHeight();
556
557 if (width <= 0 || height <= 0)
558 {
559 return false;
560 }
561
562 // The base image level is complete if the width and height are positive
563 if (level == 0)
564 {
565 return true;
566 }
567
568 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700569 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700570
571 if (image->getInternalFormat() != baseImage->getInternalFormat())
572 {
573 return false;
574 }
575
576 if (image->getWidth() != std::max(1, width >> level))
577 {
578 return false;
579 }
580
581 if (image->getHeight() != std::max(1, height >> level))
582 {
583 return false;
584 }
585
586 return true;
587}
588
589// Constructs a native texture resource from the texture images
590void TextureD3D_2D::initializeStorage(bool renderTarget)
591{
592 // Only initialize the first time this texture is used as a render target or shader resource
593 if (mTexStorage)
594 {
595 return;
596 }
597
598 // do not attempt to create storage for nonexistant data
599 if (!isLevelComplete(0))
600 {
601 return;
602 }
603
604 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
605
606 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
607 ASSERT(mTexStorage);
608
609 // flush image data to the storage
610 updateStorage();
611}
612
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400613TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614{
615 GLsizei width = getBaseLevelWidth();
616 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400617 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700618
619 ASSERT(width > 0 && height > 0);
620
621 // use existing storage level count, when previously specified by TexStorage*D
622 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
623
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400624 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625}
626
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400627void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700628{
629 SafeDelete(mTexStorage);
630 mTexStorage = newCompleteTexStorage;
631
632 if (mTexStorage && mTexStorage->isManaged())
633 {
634 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
635 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400636 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700637 }
638 }
639
640 mDirtyImages = true;
641}
642
643void TextureD3D_2D::updateStorage()
644{
645 ASSERT(mTexStorage != NULL);
646 GLint storageLevels = mTexStorage->getLevelCount();
647 for (int level = 0; level < storageLevels; level++)
648 {
649 if (mImageArray[level]->isDirty() && isLevelComplete(level))
650 {
651 updateStorageLevel(level);
652 }
653 }
654}
655
656bool TextureD3D_2D::ensureRenderTarget()
657{
658 initializeStorage(true);
659
660 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
661 {
662 ASSERT(mTexStorage);
663 if (!mTexStorage->isRenderTarget())
664 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400665 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700666
Geoff Lang9e3f24f2014-08-27 12:06:04 -0400667 if (mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700668 {
669 delete newRenderTargetStorage;
670 return gl::error(GL_OUT_OF_MEMORY, false);
671 }
672
673 setCompleteTexStorage(newRenderTargetStorage);
674 }
675 }
676
677 return (mTexStorage && mTexStorage->isRenderTarget());
678}
679
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400680TextureStorage *TextureD3D_2D::getBaseLevelStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700681{
682 return mTexStorage;
683}
684
685const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
686{
687 return mImageArray[0];
688}
689
690void TextureD3D_2D::updateStorageLevel(int level)
691{
692 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
693 ASSERT(isLevelComplete(level));
694
695 if (mImageArray[level]->isDirty())
696 {
697 commitRect(level, 0, 0, getWidth(level), getHeight(level));
698 }
699}
700
701void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
702{
703 // If there currently is a corresponding storage texture image, it has these parameters
704 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
705 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
706 const GLenum storageFormat = getBaseLevelInternalFormat();
707
708 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
709
710 if (mTexStorage)
711 {
712 const int storageLevels = mTexStorage->getLevelCount();
713
714 if ((level >= storageLevels && storageLevels != 0) ||
715 width != storageWidth ||
716 height != storageHeight ||
717 internalformat != storageFormat) // Discard mismatched storage
718 {
719 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
720 {
721 mImageArray[i]->markDirty();
722 }
723
724 SafeDelete(mTexStorage);
725 mDirtyImages = true;
726 }
727 }
728}
729
730void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
731{
732 if (isValidLevel(level))
733 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700734 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -0400735 if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700736 {
737 image->markClean();
738 }
739 }
740}
741
Brandon Jones0511e802014-07-14 16:27:26 -0700742
Brandon Jones78b1acd2014-07-15 15:33:07 -0700743TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700744 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700745 mTexStorage(NULL)
746{
747 for (int i = 0; i < 6; i++)
748 {
749 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
750 {
751 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
752 }
753 }
754}
755
756TextureD3D_Cube::~TextureD3D_Cube()
757{
Austin Kinross69822602014-08-12 15:51:37 -0700758 // Delete the Images before the TextureStorage.
759 // Images might be relying on the TextureStorage for some of their data.
760 // 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 -0700761 for (int i = 0; i < 6; i++)
762 {
763 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
764 {
765 SafeDelete(mImageArray[i][j]);
766 }
767 }
Austin Kinross69822602014-08-12 15:51:37 -0700768
769 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700770}
771
Brandon Jonescef06ff2014-08-05 13:27:48 -0700772Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700773{
774 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700775 ASSERT(layer < 6);
776 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700777}
778
Jamie Madillfeda4d22014-09-17 13:03:29 -0400779Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
780{
781 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
782 ASSERT(index.layerIndex < 6);
783 return mImageArray[index.layerIndex][index.mipIndex];
784}
785
Brandon Jonescef06ff2014-08-05 13:27:48 -0700786GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700787{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700788 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
789 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700790}
791
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700793{
794 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700795 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700796 else
797 return GL_NONE;
798}
799
Brandon Jonescef06ff2014-08-05 13:27:48 -0700800bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700801{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700803}
804
Brandon Jonescef06ff2014-08-05 13:27:48 -0700805void 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 -0700806{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700807 ASSERT(depth == 1);
808
809 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400810 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700811
812 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
813
814 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
815}
816
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817void 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 -0700818{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700819 ASSERT(depth == 1);
820
Brandon Jones0511e802014-07-14 16:27:26 -0700821 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700822 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
823
Brandon Jones0511e802014-07-14 16:27:26 -0700824 redefineImage(faceIndex, level, format, width, height);
825
826 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
827}
828
Brandon Jonescef06ff2014-08-05 13:27:48 -0700829void 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 -0700830{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700831 ASSERT(depth == 1 && zoffset == 0);
832
833 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
834
Jamie Madillfeda4d22014-09-17 13:03:29 -0400835 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
836 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700837 {
838 commitRect(faceIndex, level, xoffset, yoffset, width, height);
839 }
840}
841
Brandon Jonescef06ff2014-08-05 13:27:48 -0700842void 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 -0700843{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700844 ASSERT(depth == 1 && zoffset == 0);
845
846 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
847
Brandon Jones0511e802014-07-14 16:27:26 -0700848 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
849 {
850 commitRect(faceIndex, level, xoffset, yoffset, width, height);
851 }
852}
853
854void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
855{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700856 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400857 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
858
Brandon Jones0511e802014-07-14 16:27:26 -0700859 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
860
861 if (!mImageArray[faceIndex][level]->isRenderableFormat())
862 {
863 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
864 mDirtyImages = true;
865 }
866 else
867 {
868 ensureRenderTarget();
869 mImageArray[faceIndex][level]->markClean();
870
871 ASSERT(width == height);
872
873 if (width > 0 && isValidFaceLevel(faceIndex, level))
874 {
875 gl::Rectangle sourceRect;
876 sourceRect.x = x;
877 sourceRect.width = width;
878 sourceRect.y = y;
879 sourceRect.height = height;
880
Jamie Madill856d9d42014-09-18 15:08:49 -0400881 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700882 }
883 }
884}
885
886void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
887{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700888 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700889
890 // We can only make our texture storage to a render target if the level we're copying *to* is complete
891 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
892 // rely on the "getBaseLevel*" methods reliably otherwise.
893 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
894
895 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
896 {
897 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
898 mDirtyImages = true;
899 }
900 else
901 {
902 ensureRenderTarget();
903
904 if (isValidFaceLevel(faceIndex, level))
905 {
906 updateStorageFaceLevel(faceIndex, level);
907
908 gl::Rectangle sourceRect;
909 sourceRect.x = x;
910 sourceRect.width = width;
911 sourceRect.y = y;
912 sourceRect.height = height;
913
Jamie Madill856d9d42014-09-18 15:08:49 -0400914 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
915 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700916 }
917 }
918}
919
Brandon Jonescef06ff2014-08-05 13:27:48 -0700920void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700921{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700922 ASSERT(width == height);
923 ASSERT(depth == 1);
924
Brandon Jones0511e802014-07-14 16:27:26 -0700925 for (int level = 0; level < levels; level++)
926 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700927 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700928 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
929 {
930 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
931 }
932 }
933
934 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
935 {
936 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
937 {
938 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
939 }
940 }
941
942 mImmutable = true;
943
Jamie Madillc4833262014-09-18 16:18:26 -0400944 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400945 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
946 setCompleteTexStorage(storage);
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 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001002 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001003
Brandon Jones0511e802014-07-14 16:27:26 -07001004 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1005 {
1006 for (int level = 1; level < levelCount; level++)
1007 {
Brandon Jones0511e802014-07-14 16:27:26 -07001008 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
Jamie Madillac7579c2014-09-17 16:59:33 -04001024unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001025{
Jamie Madillc4833262014-09-18 16:18:26 -04001026 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001027}
1028
Jamie Madillac7579c2014-09-17 16:59:33 -04001029RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001030{
Jamie Madillac7579c2014-09-17 16:59:33 -04001031 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001032
1033 // ensure the underlying texture is created
1034 if (!ensureRenderTarget())
1035 {
1036 return NULL;
1037 }
1038
Jamie Madillac7579c2014-09-17 16:59:33 -04001039 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001040 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001041}
1042
Brandon Jones0511e802014-07-14 16:27:26 -07001043void TextureD3D_Cube::initializeStorage(bool renderTarget)
1044{
1045 // Only initialize the first time this texture is used as a render target or shader resource
1046 if (mTexStorage)
1047 {
1048 return;
1049 }
1050
1051 // do not attempt to create storage for nonexistant data
1052 if (!isFaceLevelComplete(0, 0))
1053 {
1054 return;
1055 }
1056
1057 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1058
1059 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1060 ASSERT(mTexStorage);
1061
1062 // flush image data to the storage
1063 updateStorage();
1064}
1065
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001066TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001067{
1068 GLsizei size = getBaseLevelWidth();
1069
1070 ASSERT(size > 0);
1071
1072 // use existing storage level count, when previously specified by TexStorage*D
1073 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1074
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001075 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001076}
1077
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001078void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001079{
1080 SafeDelete(mTexStorage);
1081 mTexStorage = newCompleteTexStorage;
1082
1083 if (mTexStorage && mTexStorage->isManaged())
1084 {
1085 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1086 {
1087 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1088 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001089 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001090 }
1091 }
1092 }
1093
1094 mDirtyImages = true;
1095}
1096
1097void TextureD3D_Cube::updateStorage()
1098{
1099 ASSERT(mTexStorage != NULL);
1100 GLint storageLevels = mTexStorage->getLevelCount();
1101 for (int face = 0; face < 6; face++)
1102 {
1103 for (int level = 0; level < storageLevels; level++)
1104 {
1105 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1106 {
1107 updateStorageFaceLevel(face, level);
1108 }
1109 }
1110 }
1111}
1112
1113bool TextureD3D_Cube::ensureRenderTarget()
1114{
1115 initializeStorage(true);
1116
1117 if (getBaseLevelWidth() > 0)
1118 {
1119 ASSERT(mTexStorage);
1120 if (!mTexStorage->isRenderTarget())
1121 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001122 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001123
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001124 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001125 {
1126 delete newRenderTargetStorage;
1127 return gl::error(GL_OUT_OF_MEMORY, false);
1128 }
1129
1130 setCompleteTexStorage(newRenderTargetStorage);
1131 }
1132 }
1133
1134 return (mTexStorage && mTexStorage->isRenderTarget());
1135}
1136
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001137TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001138{
1139 return mTexStorage;
1140}
1141
1142const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1143{
1144 // Note: if we are not cube-complete, there is no single base level image that can describe all
1145 // cube faces, so this method is only well-defined for a cube-complete base level.
1146 return mImageArray[0][0];
1147}
1148
Brandon Jones0511e802014-07-14 16:27:26 -07001149bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1150{
1151 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1152}
1153
Brandon Jones0511e802014-07-14 16:27:26 -07001154bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1155{
1156 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1157
1158 if (isImmutable())
1159 {
1160 return true;
1161 }
1162
1163 int baseSize = getBaseLevelWidth();
1164
1165 if (baseSize <= 0)
1166 {
1167 return false;
1168 }
1169
1170 // "isCubeComplete" checks for base level completeness and we must call that
1171 // to determine if any face at level 0 is complete. We omit that check here
1172 // to avoid re-checking cube-completeness for every face at level 0.
1173 if (level == 0)
1174 {
1175 return true;
1176 }
1177
1178 // Check that non-zero levels are consistent with the base level.
1179 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1180
1181 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1182 {
1183 return false;
1184 }
1185
1186 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1187 {
1188 return false;
1189 }
1190
1191 return true;
1192}
1193
1194void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1195{
1196 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1197 ImageD3D *image = mImageArray[faceIndex][level];
1198
1199 if (image->isDirty())
1200 {
1201 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1202 }
1203}
1204
1205void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1206{
1207 // If there currently is a corresponding storage texture image, it has these parameters
1208 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1209 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1210 const GLenum storageFormat = getBaseLevelInternalFormat();
1211
1212 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1213
1214 if (mTexStorage)
1215 {
1216 const int storageLevels = mTexStorage->getLevelCount();
1217
1218 if ((level >= storageLevels && storageLevels != 0) ||
1219 width != storageWidth ||
1220 height != storageHeight ||
1221 internalformat != storageFormat) // Discard mismatched storage
1222 {
1223 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1224 {
1225 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1226 {
1227 mImageArray[faceIndex][level]->markDirty();
1228 }
1229 }
1230
1231 SafeDelete(mTexStorage);
1232
1233 mDirtyImages = true;
1234 }
1235 }
1236}
1237
1238void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1239{
1240 if (isValidFaceLevel(faceIndex, level))
1241 {
1242 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001243 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001244 image->markClean();
1245 }
1246}
1247
Brandon Jones78b1acd2014-07-15 15:33:07 -07001248
1249TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001250 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001251 mTexStorage(NULL)
1252{
1253 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1254 {
1255 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1256 }
1257}
1258
1259TextureD3D_3D::~TextureD3D_3D()
1260{
Austin Kinross69822602014-08-12 15:51:37 -07001261 // Delete the Images before the TextureStorage.
1262 // Images might be relying on the TextureStorage for some of their data.
1263 // 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 -07001264 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1265 {
1266 delete mImageArray[i];
1267 }
Austin Kinross69822602014-08-12 15:51:37 -07001268
1269 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001270}
1271
Brandon Jonescef06ff2014-08-05 13:27:48 -07001272Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001273{
1274 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001275 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001276 return mImageArray[level];
1277}
1278
Jamie Madillfeda4d22014-09-17 13:03:29 -04001279Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1280{
1281 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001282 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001283 ASSERT(index.type == GL_TEXTURE_3D);
1284 return mImageArray[index.mipIndex];
1285}
1286
Brandon Jonescef06ff2014-08-05 13:27:48 -07001287GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001288{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001289 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1290 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001291}
1292
Brandon Jones78b1acd2014-07-15 15:33:07 -07001293GLsizei TextureD3D_3D::getWidth(GLint level) const
1294{
1295 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1296 return mImageArray[level]->getWidth();
1297 else
1298 return 0;
1299}
1300
1301GLsizei TextureD3D_3D::getHeight(GLint level) const
1302{
1303 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1304 return mImageArray[level]->getHeight();
1305 else
1306 return 0;
1307}
1308
1309GLsizei TextureD3D_3D::getDepth(GLint level) const
1310{
1311 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1312 return mImageArray[level]->getDepth();
1313 else
1314 return 0;
1315}
1316
1317GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1318{
1319 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1320 return mImageArray[level]->getInternalFormat();
1321 else
1322 return GL_NONE;
1323}
1324
1325bool TextureD3D_3D::isDepth(GLint level) const
1326{
Geoff Lang5d601382014-07-22 15:14:06 -04001327 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001328}
1329
Brandon Jonescef06ff2014-08-05 13:27:48 -07001330void 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 -07001331{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001332 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001333 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1334
Brandon Jones78b1acd2014-07-15 15:33:07 -07001335 redefineImage(level, sizedInternalFormat, width, height, depth);
1336
1337 bool fastUnpacked = false;
1338
1339 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1340 if (isFastUnpackable(unpack, sizedInternalFormat))
1341 {
1342 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001343 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1344 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001345 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1346
1347 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1348 {
1349 // Ensure we don't overwrite our newly initialized data
1350 mImageArray[level]->markClean();
1351
1352 fastUnpacked = true;
1353 }
1354 }
1355
1356 if (!fastUnpacked)
1357 {
1358 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1359 }
1360}
1361
Brandon Jonescef06ff2014-08-05 13:27:48 -07001362void 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 -07001363{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001364 ASSERT(target == GL_TEXTURE_3D);
1365
Brandon Jones78b1acd2014-07-15 15:33:07 -07001366 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1367 redefineImage(level, format, width, height, depth);
1368
1369 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1370}
1371
Brandon Jonescef06ff2014-08-05 13:27:48 -07001372void 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 -07001373{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001374 ASSERT(target == GL_TEXTURE_3D);
1375
Brandon Jones78b1acd2014-07-15 15:33:07 -07001376 bool fastUnpacked = false;
1377
Jamie Madillac7579c2014-09-17 16:59:33 -04001378 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1379
Brandon Jones78b1acd2014-07-15 15:33:07 -07001380 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1381 if (isFastUnpackable(unpack, getInternalFormat(level)))
1382 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001383 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001384 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1385
1386 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1387 {
1388 // Ensure we don't overwrite our newly initialized data
1389 mImageArray[level]->markClean();
1390
1391 fastUnpacked = true;
1392 }
1393 }
1394
Jamie Madillfeda4d22014-09-17 13:03:29 -04001395 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001396 {
1397 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1398 }
1399}
1400
Brandon Jonescef06ff2014-08-05 13:27:48 -07001401void 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 -07001402{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001403 ASSERT(target == GL_TEXTURE_3D);
1404
Brandon Jones78b1acd2014-07-15 15:33:07 -07001405 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1406 {
1407 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1408 }
1409}
1410
Brandon Jonescef06ff2014-08-05 13:27:48 -07001411void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1412{
1413 UNIMPLEMENTED();
1414}
1415
Brandon Jones78b1acd2014-07-15 15:33:07 -07001416void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1417{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001418 ASSERT(target == GL_TEXTURE_3D);
1419
Brandon Jones78b1acd2014-07-15 15:33:07 -07001420 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1421 // the current level we're copying to is defined (with appropriate format, width & height)
1422 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1423
1424 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1425 {
1426 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1427 mDirtyImages = true;
1428 }
1429 else
1430 {
1431 ensureRenderTarget();
1432
1433 if (isValidLevel(level))
1434 {
1435 updateStorageLevel(level);
1436
1437 gl::Rectangle sourceRect;
1438 sourceRect.x = x;
1439 sourceRect.width = width;
1440 sourceRect.y = y;
1441 sourceRect.height = height;
1442
Jamie Madill856d9d42014-09-18 15:08:49 -04001443 mRenderer->copyImage3D(source, sourceRect,
1444 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1445 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001446 }
1447 }
1448}
1449
Brandon Jonescef06ff2014-08-05 13:27:48 -07001450void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001451{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001452 ASSERT(target == GL_TEXTURE_3D);
1453
Brandon Jones78b1acd2014-07-15 15:33:07 -07001454 for (int level = 0; level < levels; level++)
1455 {
1456 GLsizei levelWidth = std::max(1, width >> level);
1457 GLsizei levelHeight = std::max(1, height >> level);
1458 GLsizei levelDepth = std::max(1, depth >> level);
1459 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1460 }
1461
1462 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1463 {
1464 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1465 }
1466
1467 mImmutable = true;
1468
Jamie Madillc4833262014-09-18 16:18:26 -04001469 bool renderTarget = IsRenderTargetUsage(mUsage);
1470 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001471 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001472}
1473
Brandon Jones6053a522014-07-25 16:22:09 -07001474void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475{
Brandon Jones6053a522014-07-25 16:22:09 -07001476 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001477}
1478
Brandon Jones6053a522014-07-25 16:22:09 -07001479void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001480{
Brandon Jones6053a522014-07-25 16:22:09 -07001481 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001482}
1483
Brandon Jones6053a522014-07-25 16:22:09 -07001484
Brandon Jones78b1acd2014-07-15 15:33:07 -07001485void TextureD3D_3D::generateMipmaps()
1486{
1487 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1488 int levelCount = mipLevels();
1489 for (int level = 1; level < levelCount; level++)
1490 {
1491 redefineImage(level, getBaseLevelInternalFormat(),
1492 std::max(getBaseLevelWidth() >> level, 1),
1493 std::max(getBaseLevelHeight() >> level, 1),
1494 std::max(getBaseLevelDepth() >> level, 1));
1495 }
1496
1497 if (mTexStorage && mTexStorage->isRenderTarget())
1498 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001499 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001500
Brandon Jones78b1acd2014-07-15 15:33:07 -07001501 for (int level = 1; level < levelCount; level++)
1502 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503 mImageArray[level]->markClean();
1504 }
1505 }
1506 else
1507 {
1508 for (int level = 1; level < levelCount; level++)
1509 {
1510 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1511 }
1512 }
1513}
1514
Jamie Madillac7579c2014-09-17 16:59:33 -04001515unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516{
Jamie Madillc4833262014-09-18 16:18:26 -04001517 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001518}
1519
Jamie Madillac7579c2014-09-17 16:59:33 -04001520RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001521{
1522 // ensure the underlying texture is created
1523 if (!ensureRenderTarget())
1524 {
1525 return NULL;
1526 }
1527
Jamie Madillac7579c2014-09-17 16:59:33 -04001528 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001529 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001530 updateStorage();
1531 }
1532 else
1533 {
1534 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535 }
1536
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001537 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001538}
1539
1540void TextureD3D_3D::initializeStorage(bool renderTarget)
1541{
1542 // Only initialize the first time this texture is used as a render target or shader resource
1543 if (mTexStorage)
1544 {
1545 return;
1546 }
1547
1548 // do not attempt to create storage for nonexistant data
1549 if (!isLevelComplete(0))
1550 {
1551 return;
1552 }
1553
1554 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1555
1556 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1557 ASSERT(mTexStorage);
1558
1559 // flush image data to the storage
1560 updateStorage();
1561}
1562
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001563TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001564{
1565 GLsizei width = getBaseLevelWidth();
1566 GLsizei height = getBaseLevelHeight();
1567 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001568 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001569
1570 ASSERT(width > 0 && height > 0 && depth > 0);
1571
1572 // use existing storage level count, when previously specified by TexStorage*D
1573 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1574
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001575 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001576}
1577
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001578void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001579{
1580 SafeDelete(mTexStorage);
1581 mTexStorage = newCompleteTexStorage;
1582 mDirtyImages = true;
1583
1584 // We do not support managed 3D storage, as that is D3D9/ES2-only
1585 ASSERT(!mTexStorage->isManaged());
1586}
1587
1588void TextureD3D_3D::updateStorage()
1589{
1590 ASSERT(mTexStorage != NULL);
1591 GLint storageLevels = mTexStorage->getLevelCount();
1592 for (int level = 0; level < storageLevels; level++)
1593 {
1594 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1595 {
1596 updateStorageLevel(level);
1597 }
1598 }
1599}
1600
1601bool TextureD3D_3D::ensureRenderTarget()
1602{
1603 initializeStorage(true);
1604
1605 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1606 {
1607 ASSERT(mTexStorage);
1608 if (!mTexStorage->isRenderTarget())
1609 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001610 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001611
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001612 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001613 {
1614 delete newRenderTargetStorage;
1615 return gl::error(GL_OUT_OF_MEMORY, false);
1616 }
1617
1618 setCompleteTexStorage(newRenderTargetStorage);
1619 }
1620 }
1621
1622 return (mTexStorage && mTexStorage->isRenderTarget());
1623}
1624
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001625TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626{
1627 return mTexStorage;
1628}
1629
1630const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1631{
1632 return mImageArray[0];
1633}
1634
1635bool TextureD3D_3D::isValidLevel(int level) const
1636{
1637 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1638}
1639
1640bool TextureD3D_3D::isLevelComplete(int level) const
1641{
1642 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1643
1644 if (isImmutable())
1645 {
1646 return true;
1647 }
1648
1649 GLsizei width = getBaseLevelWidth();
1650 GLsizei height = getBaseLevelHeight();
1651 GLsizei depth = getBaseLevelDepth();
1652
1653 if (width <= 0 || height <= 0 || depth <= 0)
1654 {
1655 return false;
1656 }
1657
1658 if (level == 0)
1659 {
1660 return true;
1661 }
1662
1663 ImageD3D *levelImage = mImageArray[level];
1664
1665 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1666 {
1667 return false;
1668 }
1669
1670 if (levelImage->getWidth() != std::max(1, width >> level))
1671 {
1672 return false;
1673 }
1674
1675 if (levelImage->getHeight() != std::max(1, height >> level))
1676 {
1677 return false;
1678 }
1679
1680 if (levelImage->getDepth() != std::max(1, depth >> level))
1681 {
1682 return false;
1683 }
1684
1685 return true;
1686}
1687
1688void TextureD3D_3D::updateStorageLevel(int level)
1689{
1690 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1691 ASSERT(isLevelComplete(level));
1692
1693 if (mImageArray[level]->isDirty())
1694 {
1695 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1696 }
1697}
1698
1699void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1700{
1701 // If there currently is a corresponding storage texture image, it has these parameters
1702 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1703 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1704 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1705 const GLenum storageFormat = getBaseLevelInternalFormat();
1706
1707 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1708
1709 if (mTexStorage)
1710 {
1711 const int storageLevels = mTexStorage->getLevelCount();
1712
1713 if ((level >= storageLevels && storageLevels != 0) ||
1714 width != storageWidth ||
1715 height != storageHeight ||
1716 depth != storageDepth ||
1717 internalformat != storageFormat) // Discard mismatched storage
1718 {
1719 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1720 {
1721 mImageArray[i]->markDirty();
1722 }
1723
1724 SafeDelete(mTexStorage);
1725 mDirtyImages = true;
1726 }
1727 }
1728}
1729
1730void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1731{
1732 if (isValidLevel(level))
1733 {
1734 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001735 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001736 {
1737 image->markClean();
1738 }
1739 }
1740}
1741
Brandon Jones142ec422014-07-16 10:31:30 -07001742
1743TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001744 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001745 mTexStorage(NULL)
1746{
1747 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1748 {
1749 mLayerCounts[level] = 0;
1750 mImageArray[level] = NULL;
1751 }
1752}
1753
1754TextureD3D_2DArray::~TextureD3D_2DArray()
1755{
Austin Kinross69822602014-08-12 15:51:37 -07001756 // Delete the Images before the TextureStorage.
1757 // Images might be relying on the TextureStorage for some of their data.
1758 // 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 -07001759 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001760 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001761}
1762
Brandon Jones142ec422014-07-16 10:31:30 -07001763Image *TextureD3D_2DArray::getImage(int level, int layer) const
1764{
1765 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1766 ASSERT(layer < mLayerCounts[level]);
1767 return mImageArray[level][layer];
1768}
1769
Jamie Madillfeda4d22014-09-17 13:03:29 -04001770Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1771{
1772 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1773 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1774 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1775 return mImageArray[index.mipIndex][index.layerIndex];
1776}
1777
Brandon Jones142ec422014-07-16 10:31:30 -07001778GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1779{
1780 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1781 return mLayerCounts[level];
1782}
1783
Brandon Jones142ec422014-07-16 10:31:30 -07001784GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1785{
1786 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1787}
1788
1789GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1790{
1791 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1792}
1793
1794GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1795{
1796 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1797}
1798
1799GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1800{
1801 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1802}
1803
1804bool TextureD3D_2DArray::isDepth(GLint level) const
1805{
Geoff Lang5d601382014-07-22 15:14:06 -04001806 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001807}
1808
Brandon Jonescef06ff2014-08-05 13:27:48 -07001809void 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 -07001810{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001811 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1812
Geoff Lang5d601382014-07-22 15:14:06 -04001813 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1814
Brandon Jones142ec422014-07-16 10:31:30 -07001815 redefineImage(level, sizedInternalFormat, width, height, depth);
1816
Geoff Lang5d601382014-07-22 15:14:06 -04001817 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1818 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001819
1820 for (int i = 0; i < depth; i++)
1821 {
1822 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1823 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1824 }
1825}
1826
Brandon Jonescef06ff2014-08-05 13:27:48 -07001827void 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 -07001828{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001829 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1830
Brandon Jones142ec422014-07-16 10:31:30 -07001831 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1832 redefineImage(level, format, width, height, depth);
1833
Geoff Lang5d601382014-07-22 15:14:06 -04001834 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1835 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001836
1837 for (int i = 0; i < depth; i++)
1838 {
1839 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1840 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1841 }
1842}
1843
Brandon Jonescef06ff2014-08-05 13:27:48 -07001844void 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 -07001845{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001846 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1847
Geoff Lang5d601382014-07-22 15:14:06 -04001848 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1849 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001850
1851 for (int i = 0; i < depth; i++)
1852 {
1853 int layer = zoffset + i;
1854 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1855
Jamie Madillfeda4d22014-09-17 13:03:29 -04001856 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1857 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001858 {
1859 commitRect(level, xoffset, yoffset, layer, width, height);
1860 }
1861 }
1862}
1863
Brandon Jonescef06ff2014-08-05 13:27:48 -07001864void 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 -07001865{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001866 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1867
Geoff Lang5d601382014-07-22 15:14:06 -04001868 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1869 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001870
1871 for (int i = 0; i < depth; i++)
1872 {
1873 int layer = zoffset + i;
1874 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1875
1876 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1877 {
1878 commitRect(level, xoffset, yoffset, layer, width, height);
1879 }
1880 }
1881}
1882
Brandon Jonescef06ff2014-08-05 13:27:48 -07001883void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1884{
1885 UNIMPLEMENTED();
1886}
1887
Brandon Jones142ec422014-07-16 10:31:30 -07001888void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1889{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001890 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1891
Brandon Jones142ec422014-07-16 10:31:30 -07001892 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1893 // the current level we're copying to is defined (with appropriate format, width & height)
1894 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1895
1896 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1897 {
1898 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1899 mDirtyImages = true;
1900 }
1901 else
1902 {
1903 ensureRenderTarget();
1904
1905 if (isValidLevel(level))
1906 {
1907 updateStorageLevel(level);
1908
1909 gl::Rectangle sourceRect;
1910 sourceRect.x = x;
1911 sourceRect.width = width;
1912 sourceRect.y = y;
1913 sourceRect.height = height;
1914
Jamie Madill856d9d42014-09-18 15:08:49 -04001915 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1916 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001917 }
1918 }
1919}
1920
Brandon Jonescef06ff2014-08-05 13:27:48 -07001921void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001922{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001923 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1924
Brandon Jones142ec422014-07-16 10:31:30 -07001925 deleteImages();
1926
1927 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1928 {
1929 GLsizei levelWidth = std::max(1, width >> level);
1930 GLsizei levelHeight = std::max(1, height >> level);
1931
1932 mLayerCounts[level] = (level < levels ? depth : 0);
1933
1934 if (mLayerCounts[level] > 0)
1935 {
1936 // Create new images for this level
1937 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1938
1939 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1940 {
1941 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1942 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1943 levelHeight, 1, true);
1944 }
1945 }
1946 }
1947
1948 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001949
1950 bool renderTarget = IsRenderTargetUsage(mUsage);
1951 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001952 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07001953}
1954
Brandon Jones6053a522014-07-25 16:22:09 -07001955void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001956{
Brandon Jones6053a522014-07-25 16:22:09 -07001957 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001958}
1959
Brandon Jones6053a522014-07-25 16:22:09 -07001960void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001961{
Brandon Jones6053a522014-07-25 16:22:09 -07001962 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001963}
1964
Brandon Jones6053a522014-07-25 16:22:09 -07001965
Brandon Jones142ec422014-07-16 10:31:30 -07001966void TextureD3D_2DArray::generateMipmaps()
1967{
1968 int baseWidth = getBaseLevelWidth();
1969 int baseHeight = getBaseLevelHeight();
1970 int baseDepth = getBaseLevelDepth();
1971 GLenum baseFormat = getBaseLevelInternalFormat();
1972
1973 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1974 int levelCount = mipLevels();
1975 for (int level = 1; level < levelCount; level++)
1976 {
1977 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1978 }
1979
1980 if (mTexStorage && mTexStorage->isRenderTarget())
1981 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001982 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001983
Brandon Jones142ec422014-07-16 10:31:30 -07001984 for (int level = 1; level < levelCount; level++)
1985 {
Brandon Jones142ec422014-07-16 10:31:30 -07001986 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1987 {
1988 mImageArray[level][layer]->markClean();
1989 }
1990 }
1991 }
1992 else
1993 {
1994 for (int level = 1; level < levelCount; level++)
1995 {
1996 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1997 {
1998 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
1999 }
2000 }
2001 }
2002}
2003
Jamie Madillac7579c2014-09-17 16:59:33 -04002004unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002005{
Jamie Madillc4833262014-09-18 16:18:26 -04002006 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002007}
2008
Jamie Madillac7579c2014-09-17 16:59:33 -04002009RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002010{
2011 // ensure the underlying texture is created
2012 if (!ensureRenderTarget())
2013 {
2014 return NULL;
2015 }
2016
Jamie Madillac7579c2014-09-17 16:59:33 -04002017 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002018 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002019}
2020
2021void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2022{
2023 // Only initialize the first time this texture is used as a render target or shader resource
2024 if (mTexStorage)
2025 {
2026 return;
2027 }
2028
2029 // do not attempt to create storage for nonexistant data
2030 if (!isLevelComplete(0))
2031 {
2032 return;
2033 }
2034
2035 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2036
2037 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2038 ASSERT(mTexStorage);
2039
2040 // flush image data to the storage
2041 updateStorage();
2042}
2043
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002044TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002045{
2046 GLsizei width = getBaseLevelWidth();
2047 GLsizei height = getBaseLevelHeight();
2048 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002049 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002050
2051 ASSERT(width > 0 && height > 0 && depth > 0);
2052
2053 // use existing storage level count, when previously specified by TexStorage*D
2054 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2055
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002056 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002057}
2058
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002059void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002060{
2061 SafeDelete(mTexStorage);
2062 mTexStorage = newCompleteTexStorage;
2063 mDirtyImages = true;
2064
2065 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2066 ASSERT(!mTexStorage->isManaged());
2067}
2068
2069void TextureD3D_2DArray::updateStorage()
2070{
2071 ASSERT(mTexStorage != NULL);
2072 GLint storageLevels = mTexStorage->getLevelCount();
2073 for (int level = 0; level < storageLevels; level++)
2074 {
2075 if (isLevelComplete(level))
2076 {
2077 updateStorageLevel(level);
2078 }
2079 }
2080}
2081
2082bool TextureD3D_2DArray::ensureRenderTarget()
2083{
2084 initializeStorage(true);
2085
2086 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2087 {
2088 ASSERT(mTexStorage);
2089 if (!mTexStorage->isRenderTarget())
2090 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002091 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002092
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002093 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002094 {
2095 delete newRenderTargetStorage;
2096 return gl::error(GL_OUT_OF_MEMORY, false);
2097 }
2098
2099 setCompleteTexStorage(newRenderTargetStorage);
2100 }
2101 }
2102
2103 return (mTexStorage && mTexStorage->isRenderTarget());
2104}
2105
2106const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2107{
2108 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2109}
2110
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002111TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002112{
2113 return mTexStorage;
2114}
2115
2116bool TextureD3D_2DArray::isValidLevel(int level) const
2117{
2118 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2119}
2120
2121bool TextureD3D_2DArray::isLevelComplete(int level) const
2122{
2123 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2124
2125 if (isImmutable())
2126 {
2127 return true;
2128 }
2129
2130 GLsizei width = getBaseLevelWidth();
2131 GLsizei height = getBaseLevelHeight();
2132 GLsizei layers = getLayers(0);
2133
2134 if (width <= 0 || height <= 0 || layers <= 0)
2135 {
2136 return false;
2137 }
2138
2139 if (level == 0)
2140 {
2141 return true;
2142 }
2143
2144 if (getInternalFormat(level) != getInternalFormat(0))
2145 {
2146 return false;
2147 }
2148
2149 if (getWidth(level) != std::max(1, width >> level))
2150 {
2151 return false;
2152 }
2153
2154 if (getHeight(level) != std::max(1, height >> level))
2155 {
2156 return false;
2157 }
2158
2159 if (getLayers(level) != layers)
2160 {
2161 return false;
2162 }
2163
2164 return true;
2165}
2166
2167void TextureD3D_2DArray::updateStorageLevel(int level)
2168{
2169 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2170 ASSERT(isLevelComplete(level));
2171
2172 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2173 {
2174 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2175 if (mImageArray[level][layer]->isDirty())
2176 {
2177 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2178 }
2179 }
2180}
2181
2182void TextureD3D_2DArray::deleteImages()
2183{
2184 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2185 {
2186 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2187 {
2188 delete mImageArray[level][layer];
2189 }
2190 delete[] mImageArray[level];
2191 mImageArray[level] = NULL;
2192 mLayerCounts[level] = 0;
2193 }
2194}
2195
2196void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2197{
2198 // If there currently is a corresponding storage texture image, it has these parameters
2199 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2200 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2201 const int storageDepth = getLayers(0);
2202 const GLenum storageFormat = getBaseLevelInternalFormat();
2203
2204 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2205 {
2206 delete mImageArray[level][layer];
2207 }
2208 delete[] mImageArray[level];
2209 mImageArray[level] = NULL;
2210 mLayerCounts[level] = depth;
2211
2212 if (depth > 0)
2213 {
2214 mImageArray[level] = new ImageD3D*[depth]();
2215
2216 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2217 {
2218 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2219 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2220 }
2221 }
2222
2223 if (mTexStorage)
2224 {
2225 const int storageLevels = mTexStorage->getLevelCount();
2226
2227 if ((level >= storageLevels && storageLevels != 0) ||
2228 width != storageWidth ||
2229 height != storageHeight ||
2230 depth != storageDepth ||
2231 internalformat != storageFormat) // Discard mismatched storage
2232 {
2233 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2234 {
2235 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2236 {
2237 mImageArray[level][layer]->markDirty();
2238 }
2239 }
2240
2241 delete mTexStorage;
2242 mTexStorage = NULL;
2243 mDirtyImages = true;
2244 }
2245 }
2246}
2247
2248void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2249{
2250 if (isValidLevel(level) && layerTarget < getLayers(level))
2251 {
2252 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002253 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002254 {
2255 image->markClean();
2256 }
2257 }
2258}
2259
Brandon Jones78b1acd2014-07-15 15:33:07 -07002260}