blob: e522b85520d9bf21f6d349c5553463d34c1ec3c4 [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
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400742gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
743{
744 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
745}
Brandon Jones0511e802014-07-14 16:27:26 -0700746
Brandon Jones78b1acd2014-07-15 15:33:07 -0700747TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700748 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700749 mTexStorage(NULL)
750{
751 for (int i = 0; i < 6; i++)
752 {
753 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
754 {
755 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
756 }
757 }
758}
759
760TextureD3D_Cube::~TextureD3D_Cube()
761{
Austin Kinross69822602014-08-12 15:51:37 -0700762 // Delete the Images before the TextureStorage.
763 // Images might be relying on the TextureStorage for some of their data.
764 // 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 -0700765 for (int i = 0; i < 6; i++)
766 {
767 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
768 {
769 SafeDelete(mImageArray[i][j]);
770 }
771 }
Austin Kinross69822602014-08-12 15:51:37 -0700772
773 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700774}
775
Brandon Jonescef06ff2014-08-05 13:27:48 -0700776Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700777{
778 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700779 ASSERT(layer < 6);
780 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700781}
782
Jamie Madillfeda4d22014-09-17 13:03:29 -0400783Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
784{
785 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
786 ASSERT(index.layerIndex < 6);
787 return mImageArray[index.layerIndex][index.mipIndex];
788}
789
Brandon Jonescef06ff2014-08-05 13:27:48 -0700790GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700791{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
793 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700794}
795
Brandon Jonescef06ff2014-08-05 13:27:48 -0700796GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700797{
798 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700799 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700800 else
801 return GL_NONE;
802}
803
Brandon Jonescef06ff2014-08-05 13:27:48 -0700804bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700805{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700806 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700807}
808
Brandon Jonescef06ff2014-08-05 13:27:48 -0700809void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700810{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700811 ASSERT(depth == 1);
812
813 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400814 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700815
816 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
817
818 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
819}
820
Brandon Jonescef06ff2014-08-05 13:27:48 -0700821void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700822{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700823 ASSERT(depth == 1);
824
Brandon Jones0511e802014-07-14 16:27:26 -0700825 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700826 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
827
Brandon Jones0511e802014-07-14 16:27:26 -0700828 redefineImage(faceIndex, level, format, width, height);
829
830 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
831}
832
Brandon Jonescef06ff2014-08-05 13:27:48 -0700833void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700834{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700835 ASSERT(depth == 1 && zoffset == 0);
836
837 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
838
Jamie Madillfeda4d22014-09-17 13:03:29 -0400839 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
840 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700841 {
842 commitRect(faceIndex, level, xoffset, yoffset, width, height);
843 }
844}
845
Brandon Jonescef06ff2014-08-05 13:27:48 -0700846void 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 -0700847{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700848 ASSERT(depth == 1 && zoffset == 0);
849
850 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
851
Brandon Jones0511e802014-07-14 16:27:26 -0700852 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
853 {
854 commitRect(faceIndex, level, xoffset, yoffset, width, height);
855 }
856}
857
858void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
859{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700860 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400861 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
862
Brandon Jones0511e802014-07-14 16:27:26 -0700863 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
864
865 if (!mImageArray[faceIndex][level]->isRenderableFormat())
866 {
867 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
868 mDirtyImages = true;
869 }
870 else
871 {
872 ensureRenderTarget();
873 mImageArray[faceIndex][level]->markClean();
874
875 ASSERT(width == height);
876
877 if (width > 0 && isValidFaceLevel(faceIndex, level))
878 {
879 gl::Rectangle sourceRect;
880 sourceRect.x = x;
881 sourceRect.width = width;
882 sourceRect.y = y;
883 sourceRect.height = height;
884
Jamie Madill856d9d42014-09-18 15:08:49 -0400885 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700886 }
887 }
888}
889
890void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
891{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700892 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700893
894 // We can only make our texture storage to a render target if the level we're copying *to* is complete
895 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
896 // rely on the "getBaseLevel*" methods reliably otherwise.
897 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
898
899 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
900 {
901 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
902 mDirtyImages = true;
903 }
904 else
905 {
906 ensureRenderTarget();
907
908 if (isValidFaceLevel(faceIndex, level))
909 {
910 updateStorageFaceLevel(faceIndex, level);
911
912 gl::Rectangle sourceRect;
913 sourceRect.x = x;
914 sourceRect.width = width;
915 sourceRect.y = y;
916 sourceRect.height = height;
917
Jamie Madill856d9d42014-09-18 15:08:49 -0400918 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
919 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700920 }
921 }
922}
923
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700925{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700926 ASSERT(width == height);
927 ASSERT(depth == 1);
928
Brandon Jones0511e802014-07-14 16:27:26 -0700929 for (int level = 0; level < levels; level++)
930 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700931 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700932 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
933 {
934 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
935 }
936 }
937
938 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
939 {
940 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
941 {
942 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
943 }
944 }
945
946 mImmutable = true;
947
Jamie Madillc4833262014-09-18 16:18:26 -0400948 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400949 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
950 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -0700951}
952
Brandon Jones0511e802014-07-14 16:27:26 -0700953// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
954bool TextureD3D_Cube::isCubeComplete() const
955{
956 int baseWidth = getBaseLevelWidth();
957 int baseHeight = getBaseLevelHeight();
958 GLenum baseFormat = getBaseLevelInternalFormat();
959
960 if (baseWidth <= 0 || baseWidth != baseHeight)
961 {
962 return false;
963 }
964
965 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
966 {
967 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
968
969 if (faceBaseImage.getWidth() != baseWidth ||
970 faceBaseImage.getHeight() != baseHeight ||
971 faceBaseImage.getInternalFormat() != baseFormat )
972 {
973 return false;
974 }
975 }
976
977 return true;
978}
979
Brandon Jones6053a522014-07-25 16:22:09 -0700980void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
981{
982 UNREACHABLE();
983}
984
985void TextureD3D_Cube::releaseTexImage()
986{
987 UNREACHABLE();
988}
989
990
Brandon Jones0511e802014-07-14 16:27:26 -0700991void TextureD3D_Cube::generateMipmaps()
992{
993 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
994 int levelCount = mipLevels();
995 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
996 {
997 for (int level = 1; level < levelCount; level++)
998 {
999 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1000 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1001 }
1002 }
1003
1004 if (mTexStorage && mTexStorage->isRenderTarget())
1005 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001006 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001007
Brandon Jones0511e802014-07-14 16:27:26 -07001008 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1009 {
1010 for (int level = 1; level < levelCount; level++)
1011 {
Brandon Jones0511e802014-07-14 16:27:26 -07001012 mImageArray[faceIndex][level]->markClean();
1013 }
1014 }
1015 }
1016 else
1017 {
1018 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1019 {
1020 for (int level = 1; level < levelCount; level++)
1021 {
1022 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1023 }
1024 }
1025 }
1026}
1027
Jamie Madillac7579c2014-09-17 16:59:33 -04001028unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001029{
Jamie Madillc4833262014-09-18 16:18:26 -04001030 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001031}
1032
Jamie Madillac7579c2014-09-17 16:59:33 -04001033RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001034{
Jamie Madillac7579c2014-09-17 16:59:33 -04001035 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001036
1037 // ensure the underlying texture is created
1038 if (!ensureRenderTarget())
1039 {
1040 return NULL;
1041 }
1042
Jamie Madillac7579c2014-09-17 16:59:33 -04001043 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001044 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001045}
1046
Brandon Jones0511e802014-07-14 16:27:26 -07001047void TextureD3D_Cube::initializeStorage(bool renderTarget)
1048{
1049 // Only initialize the first time this texture is used as a render target or shader resource
1050 if (mTexStorage)
1051 {
1052 return;
1053 }
1054
1055 // do not attempt to create storage for nonexistant data
1056 if (!isFaceLevelComplete(0, 0))
1057 {
1058 return;
1059 }
1060
1061 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1062
1063 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1064 ASSERT(mTexStorage);
1065
1066 // flush image data to the storage
1067 updateStorage();
1068}
1069
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001070TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001071{
1072 GLsizei size = getBaseLevelWidth();
1073
1074 ASSERT(size > 0);
1075
1076 // use existing storage level count, when previously specified by TexStorage*D
1077 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1078
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001079 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001080}
1081
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001082void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001083{
1084 SafeDelete(mTexStorage);
1085 mTexStorage = newCompleteTexStorage;
1086
1087 if (mTexStorage && mTexStorage->isManaged())
1088 {
1089 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1090 {
1091 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1092 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001093 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001094 }
1095 }
1096 }
1097
1098 mDirtyImages = true;
1099}
1100
1101void TextureD3D_Cube::updateStorage()
1102{
1103 ASSERT(mTexStorage != NULL);
1104 GLint storageLevels = mTexStorage->getLevelCount();
1105 for (int face = 0; face < 6; face++)
1106 {
1107 for (int level = 0; level < storageLevels; level++)
1108 {
1109 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1110 {
1111 updateStorageFaceLevel(face, level);
1112 }
1113 }
1114 }
1115}
1116
1117bool TextureD3D_Cube::ensureRenderTarget()
1118{
1119 initializeStorage(true);
1120
1121 if (getBaseLevelWidth() > 0)
1122 {
1123 ASSERT(mTexStorage);
1124 if (!mTexStorage->isRenderTarget())
1125 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001126 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001127
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001128 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001129 {
1130 delete newRenderTargetStorage;
1131 return gl::error(GL_OUT_OF_MEMORY, false);
1132 }
1133
1134 setCompleteTexStorage(newRenderTargetStorage);
1135 }
1136 }
1137
1138 return (mTexStorage && mTexStorage->isRenderTarget());
1139}
1140
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001141TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001142{
1143 return mTexStorage;
1144}
1145
1146const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1147{
1148 // Note: if we are not cube-complete, there is no single base level image that can describe all
1149 // cube faces, so this method is only well-defined for a cube-complete base level.
1150 return mImageArray[0][0];
1151}
1152
Brandon Jones0511e802014-07-14 16:27:26 -07001153bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1154{
1155 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1156}
1157
Brandon Jones0511e802014-07-14 16:27:26 -07001158bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1159{
1160 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1161
1162 if (isImmutable())
1163 {
1164 return true;
1165 }
1166
1167 int baseSize = getBaseLevelWidth();
1168
1169 if (baseSize <= 0)
1170 {
1171 return false;
1172 }
1173
1174 // "isCubeComplete" checks for base level completeness and we must call that
1175 // to determine if any face at level 0 is complete. We omit that check here
1176 // to avoid re-checking cube-completeness for every face at level 0.
1177 if (level == 0)
1178 {
1179 return true;
1180 }
1181
1182 // Check that non-zero levels are consistent with the base level.
1183 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1184
1185 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1186 {
1187 return false;
1188 }
1189
1190 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1191 {
1192 return false;
1193 }
1194
1195 return true;
1196}
1197
1198void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1199{
1200 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1201 ImageD3D *image = mImageArray[faceIndex][level];
1202
1203 if (image->isDirty())
1204 {
1205 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1206 }
1207}
1208
1209void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1210{
1211 // If there currently is a corresponding storage texture image, it has these parameters
1212 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1213 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1214 const GLenum storageFormat = getBaseLevelInternalFormat();
1215
1216 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1217
1218 if (mTexStorage)
1219 {
1220 const int storageLevels = mTexStorage->getLevelCount();
1221
1222 if ((level >= storageLevels && storageLevels != 0) ||
1223 width != storageWidth ||
1224 height != storageHeight ||
1225 internalformat != storageFormat) // Discard mismatched storage
1226 {
1227 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1228 {
1229 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1230 {
1231 mImageArray[faceIndex][level]->markDirty();
1232 }
1233 }
1234
1235 SafeDelete(mTexStorage);
1236
1237 mDirtyImages = true;
1238 }
1239 }
1240}
1241
1242void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1243{
1244 if (isValidFaceLevel(faceIndex, level))
1245 {
1246 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001247 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001248 image->markClean();
1249 }
1250}
1251
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001252gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1253{
1254 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1255}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001256
1257TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001258 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001259 mTexStorage(NULL)
1260{
1261 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1262 {
1263 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1264 }
1265}
1266
1267TextureD3D_3D::~TextureD3D_3D()
1268{
Austin Kinross69822602014-08-12 15:51:37 -07001269 // Delete the Images before the TextureStorage.
1270 // Images might be relying on the TextureStorage for some of their data.
1271 // 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 -07001272 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1273 {
1274 delete mImageArray[i];
1275 }
Austin Kinross69822602014-08-12 15:51:37 -07001276
1277 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001278}
1279
Brandon Jonescef06ff2014-08-05 13:27:48 -07001280Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001281{
1282 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001283 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001284 return mImageArray[level];
1285}
1286
Jamie Madillfeda4d22014-09-17 13:03:29 -04001287Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1288{
1289 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001290 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001291 ASSERT(index.type == GL_TEXTURE_3D);
1292 return mImageArray[index.mipIndex];
1293}
1294
Brandon Jonescef06ff2014-08-05 13:27:48 -07001295GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001296{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001297 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1298 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001299}
1300
Brandon Jones78b1acd2014-07-15 15:33:07 -07001301GLsizei TextureD3D_3D::getWidth(GLint level) const
1302{
1303 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1304 return mImageArray[level]->getWidth();
1305 else
1306 return 0;
1307}
1308
1309GLsizei TextureD3D_3D::getHeight(GLint level) const
1310{
1311 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1312 return mImageArray[level]->getHeight();
1313 else
1314 return 0;
1315}
1316
1317GLsizei TextureD3D_3D::getDepth(GLint level) const
1318{
1319 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1320 return mImageArray[level]->getDepth();
1321 else
1322 return 0;
1323}
1324
1325GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1326{
1327 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1328 return mImageArray[level]->getInternalFormat();
1329 else
1330 return GL_NONE;
1331}
1332
1333bool TextureD3D_3D::isDepth(GLint level) const
1334{
Geoff Lang5d601382014-07-22 15:14:06 -04001335 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001336}
1337
Brandon Jonescef06ff2014-08-05 13:27:48 -07001338void 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 -07001339{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001340 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001341 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1342
Brandon Jones78b1acd2014-07-15 15:33:07 -07001343 redefineImage(level, sizedInternalFormat, width, height, depth);
1344
1345 bool fastUnpacked = false;
1346
1347 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1348 if (isFastUnpackable(unpack, sizedInternalFormat))
1349 {
1350 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001351 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1352 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001353 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1354
1355 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1356 {
1357 // Ensure we don't overwrite our newly initialized data
1358 mImageArray[level]->markClean();
1359
1360 fastUnpacked = true;
1361 }
1362 }
1363
1364 if (!fastUnpacked)
1365 {
1366 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1367 }
1368}
1369
Brandon Jonescef06ff2014-08-05 13:27:48 -07001370void 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 -07001371{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001372 ASSERT(target == GL_TEXTURE_3D);
1373
Brandon Jones78b1acd2014-07-15 15:33:07 -07001374 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1375 redefineImage(level, format, width, height, depth);
1376
1377 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1378}
1379
Brandon Jonescef06ff2014-08-05 13:27:48 -07001380void 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 -07001381{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001382 ASSERT(target == GL_TEXTURE_3D);
1383
Brandon Jones78b1acd2014-07-15 15:33:07 -07001384 bool fastUnpacked = false;
1385
Jamie Madillac7579c2014-09-17 16:59:33 -04001386 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1387
Brandon Jones78b1acd2014-07-15 15:33:07 -07001388 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1389 if (isFastUnpackable(unpack, getInternalFormat(level)))
1390 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001391 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001392 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1393
1394 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1395 {
1396 // Ensure we don't overwrite our newly initialized data
1397 mImageArray[level]->markClean();
1398
1399 fastUnpacked = true;
1400 }
1401 }
1402
Jamie Madillfeda4d22014-09-17 13:03:29 -04001403 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001404 {
1405 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1406 }
1407}
1408
Brandon Jonescef06ff2014-08-05 13:27:48 -07001409void 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 -07001410{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001411 ASSERT(target == GL_TEXTURE_3D);
1412
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1414 {
1415 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1416 }
1417}
1418
Brandon Jonescef06ff2014-08-05 13:27:48 -07001419void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1420{
1421 UNIMPLEMENTED();
1422}
1423
Brandon Jones78b1acd2014-07-15 15:33:07 -07001424void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1425{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001426 ASSERT(target == GL_TEXTURE_3D);
1427
Brandon Jones78b1acd2014-07-15 15:33:07 -07001428 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1429 // the current level we're copying to is defined (with appropriate format, width & height)
1430 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1431
1432 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1433 {
1434 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1435 mDirtyImages = true;
1436 }
1437 else
1438 {
1439 ensureRenderTarget();
1440
1441 if (isValidLevel(level))
1442 {
1443 updateStorageLevel(level);
1444
1445 gl::Rectangle sourceRect;
1446 sourceRect.x = x;
1447 sourceRect.width = width;
1448 sourceRect.y = y;
1449 sourceRect.height = height;
1450
Jamie Madill856d9d42014-09-18 15:08:49 -04001451 mRenderer->copyImage3D(source, sourceRect,
1452 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1453 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001454 }
1455 }
1456}
1457
Brandon Jonescef06ff2014-08-05 13:27:48 -07001458void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001459{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001460 ASSERT(target == GL_TEXTURE_3D);
1461
Brandon Jones78b1acd2014-07-15 15:33:07 -07001462 for (int level = 0; level < levels; level++)
1463 {
1464 GLsizei levelWidth = std::max(1, width >> level);
1465 GLsizei levelHeight = std::max(1, height >> level);
1466 GLsizei levelDepth = std::max(1, depth >> level);
1467 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1468 }
1469
1470 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1471 {
1472 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1473 }
1474
1475 mImmutable = true;
1476
Jamie Madillc4833262014-09-18 16:18:26 -04001477 bool renderTarget = IsRenderTargetUsage(mUsage);
1478 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001479 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001480}
1481
Brandon Jones6053a522014-07-25 16:22:09 -07001482void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001483{
Brandon Jones6053a522014-07-25 16:22:09 -07001484 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001485}
1486
Brandon Jones6053a522014-07-25 16:22:09 -07001487void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001488{
Brandon Jones6053a522014-07-25 16:22:09 -07001489 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001490}
1491
Brandon Jones6053a522014-07-25 16:22:09 -07001492
Brandon Jones78b1acd2014-07-15 15:33:07 -07001493void TextureD3D_3D::generateMipmaps()
1494{
1495 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1496 int levelCount = mipLevels();
1497 for (int level = 1; level < levelCount; level++)
1498 {
1499 redefineImage(level, getBaseLevelInternalFormat(),
1500 std::max(getBaseLevelWidth() >> level, 1),
1501 std::max(getBaseLevelHeight() >> level, 1),
1502 std::max(getBaseLevelDepth() >> level, 1));
1503 }
1504
1505 if (mTexStorage && mTexStorage->isRenderTarget())
1506 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001507 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001508
Brandon Jones78b1acd2014-07-15 15:33:07 -07001509 for (int level = 1; level < levelCount; level++)
1510 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511 mImageArray[level]->markClean();
1512 }
1513 }
1514 else
1515 {
1516 for (int level = 1; level < levelCount; level++)
1517 {
1518 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1519 }
1520 }
1521}
1522
Jamie Madillac7579c2014-09-17 16:59:33 -04001523unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001524{
Jamie Madillc4833262014-09-18 16:18:26 -04001525 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001526}
1527
Jamie Madillac7579c2014-09-17 16:59:33 -04001528RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001529{
1530 // ensure the underlying texture is created
1531 if (!ensureRenderTarget())
1532 {
1533 return NULL;
1534 }
1535
Jamie Madillac7579c2014-09-17 16:59:33 -04001536 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001537 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001538 updateStorage();
1539 }
1540 else
1541 {
1542 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001543 }
1544
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001545 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001546}
1547
1548void TextureD3D_3D::initializeStorage(bool renderTarget)
1549{
1550 // Only initialize the first time this texture is used as a render target or shader resource
1551 if (mTexStorage)
1552 {
1553 return;
1554 }
1555
1556 // do not attempt to create storage for nonexistant data
1557 if (!isLevelComplete(0))
1558 {
1559 return;
1560 }
1561
1562 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1563
1564 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1565 ASSERT(mTexStorage);
1566
1567 // flush image data to the storage
1568 updateStorage();
1569}
1570
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001571TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001572{
1573 GLsizei width = getBaseLevelWidth();
1574 GLsizei height = getBaseLevelHeight();
1575 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001576 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001577
1578 ASSERT(width > 0 && height > 0 && depth > 0);
1579
1580 // use existing storage level count, when previously specified by TexStorage*D
1581 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1582
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001583 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001584}
1585
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001586void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001587{
1588 SafeDelete(mTexStorage);
1589 mTexStorage = newCompleteTexStorage;
1590 mDirtyImages = true;
1591
1592 // We do not support managed 3D storage, as that is D3D9/ES2-only
1593 ASSERT(!mTexStorage->isManaged());
1594}
1595
1596void TextureD3D_3D::updateStorage()
1597{
1598 ASSERT(mTexStorage != NULL);
1599 GLint storageLevels = mTexStorage->getLevelCount();
1600 for (int level = 0; level < storageLevels; level++)
1601 {
1602 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1603 {
1604 updateStorageLevel(level);
1605 }
1606 }
1607}
1608
1609bool TextureD3D_3D::ensureRenderTarget()
1610{
1611 initializeStorage(true);
1612
1613 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1614 {
1615 ASSERT(mTexStorage);
1616 if (!mTexStorage->isRenderTarget())
1617 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001618 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001619
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001620 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001621 {
1622 delete newRenderTargetStorage;
1623 return gl::error(GL_OUT_OF_MEMORY, false);
1624 }
1625
1626 setCompleteTexStorage(newRenderTargetStorage);
1627 }
1628 }
1629
1630 return (mTexStorage && mTexStorage->isRenderTarget());
1631}
1632
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001633TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634{
1635 return mTexStorage;
1636}
1637
1638const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1639{
1640 return mImageArray[0];
1641}
1642
1643bool TextureD3D_3D::isValidLevel(int level) const
1644{
1645 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1646}
1647
1648bool TextureD3D_3D::isLevelComplete(int level) const
1649{
1650 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1651
1652 if (isImmutable())
1653 {
1654 return true;
1655 }
1656
1657 GLsizei width = getBaseLevelWidth();
1658 GLsizei height = getBaseLevelHeight();
1659 GLsizei depth = getBaseLevelDepth();
1660
1661 if (width <= 0 || height <= 0 || depth <= 0)
1662 {
1663 return false;
1664 }
1665
1666 if (level == 0)
1667 {
1668 return true;
1669 }
1670
1671 ImageD3D *levelImage = mImageArray[level];
1672
1673 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1674 {
1675 return false;
1676 }
1677
1678 if (levelImage->getWidth() != std::max(1, width >> level))
1679 {
1680 return false;
1681 }
1682
1683 if (levelImage->getHeight() != std::max(1, height >> level))
1684 {
1685 return false;
1686 }
1687
1688 if (levelImage->getDepth() != std::max(1, depth >> level))
1689 {
1690 return false;
1691 }
1692
1693 return true;
1694}
1695
1696void TextureD3D_3D::updateStorageLevel(int level)
1697{
1698 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1699 ASSERT(isLevelComplete(level));
1700
1701 if (mImageArray[level]->isDirty())
1702 {
1703 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1704 }
1705}
1706
1707void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1708{
1709 // If there currently is a corresponding storage texture image, it has these parameters
1710 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1711 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1712 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1713 const GLenum storageFormat = getBaseLevelInternalFormat();
1714
1715 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1716
1717 if (mTexStorage)
1718 {
1719 const int storageLevels = mTexStorage->getLevelCount();
1720
1721 if ((level >= storageLevels && storageLevels != 0) ||
1722 width != storageWidth ||
1723 height != storageHeight ||
1724 depth != storageDepth ||
1725 internalformat != storageFormat) // Discard mismatched storage
1726 {
1727 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1728 {
1729 mImageArray[i]->markDirty();
1730 }
1731
1732 SafeDelete(mTexStorage);
1733 mDirtyImages = true;
1734 }
1735 }
1736}
1737
1738void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1739{
1740 if (isValidLevel(level))
1741 {
1742 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001743 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001744 {
1745 image->markClean();
1746 }
1747 }
1748}
1749
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001750gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1751{
1752 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1753 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1754}
Brandon Jones142ec422014-07-16 10:31:30 -07001755
1756TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001757 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001758 mTexStorage(NULL)
1759{
1760 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1761 {
1762 mLayerCounts[level] = 0;
1763 mImageArray[level] = NULL;
1764 }
1765}
1766
1767TextureD3D_2DArray::~TextureD3D_2DArray()
1768{
Austin Kinross69822602014-08-12 15:51:37 -07001769 // Delete the Images before the TextureStorage.
1770 // Images might be relying on the TextureStorage for some of their data.
1771 // 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 -07001772 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001773 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001774}
1775
Brandon Jones142ec422014-07-16 10:31:30 -07001776Image *TextureD3D_2DArray::getImage(int level, int layer) const
1777{
1778 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1779 ASSERT(layer < mLayerCounts[level]);
1780 return mImageArray[level][layer];
1781}
1782
Jamie Madillfeda4d22014-09-17 13:03:29 -04001783Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1784{
1785 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1786 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1787 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1788 return mImageArray[index.mipIndex][index.layerIndex];
1789}
1790
Brandon Jones142ec422014-07-16 10:31:30 -07001791GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1792{
1793 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1794 return mLayerCounts[level];
1795}
1796
Brandon Jones142ec422014-07-16 10:31:30 -07001797GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1798{
1799 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1800}
1801
1802GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1803{
1804 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1805}
1806
1807GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1808{
1809 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1810}
1811
1812GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1813{
1814 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1815}
1816
1817bool TextureD3D_2DArray::isDepth(GLint level) const
1818{
Geoff Lang5d601382014-07-22 15:14:06 -04001819 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001820}
1821
Brandon Jonescef06ff2014-08-05 13:27:48 -07001822void 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 -07001823{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001824 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1825
Geoff Lang5d601382014-07-22 15:14:06 -04001826 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1827
Brandon Jones142ec422014-07-16 10:31:30 -07001828 redefineImage(level, sizedInternalFormat, width, height, depth);
1829
Geoff Lang5d601382014-07-22 15:14:06 -04001830 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1831 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001832
1833 for (int i = 0; i < depth; i++)
1834 {
1835 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1836 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1837 }
1838}
1839
Brandon Jonescef06ff2014-08-05 13:27:48 -07001840void 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 -07001841{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001842 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1843
Brandon Jones142ec422014-07-16 10:31:30 -07001844 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1845 redefineImage(level, format, width, height, depth);
1846
Geoff Lang5d601382014-07-22 15:14:06 -04001847 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1848 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001849
1850 for (int i = 0; i < depth; i++)
1851 {
1852 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1853 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1854 }
1855}
1856
Brandon Jonescef06ff2014-08-05 13:27:48 -07001857void 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 -07001858{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001859 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1860
Geoff Lang5d601382014-07-22 15:14:06 -04001861 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1862 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001863
1864 for (int i = 0; i < depth; i++)
1865 {
1866 int layer = zoffset + i;
1867 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1868
Jamie Madillfeda4d22014-09-17 13:03:29 -04001869 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1870 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001871 {
1872 commitRect(level, xoffset, yoffset, layer, width, height);
1873 }
1874 }
1875}
1876
Brandon Jonescef06ff2014-08-05 13:27:48 -07001877void 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 -07001878{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001879 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1880
Geoff Lang5d601382014-07-22 15:14:06 -04001881 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1882 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001883
1884 for (int i = 0; i < depth; i++)
1885 {
1886 int layer = zoffset + i;
1887 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1888
1889 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1890 {
1891 commitRect(level, xoffset, yoffset, layer, width, height);
1892 }
1893 }
1894}
1895
Brandon Jonescef06ff2014-08-05 13:27:48 -07001896void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1897{
1898 UNIMPLEMENTED();
1899}
1900
Brandon Jones142ec422014-07-16 10:31:30 -07001901void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1902{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001903 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1904
Brandon Jones142ec422014-07-16 10:31:30 -07001905 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1906 // the current level we're copying to is defined (with appropriate format, width & height)
1907 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1908
1909 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1910 {
1911 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1912 mDirtyImages = true;
1913 }
1914 else
1915 {
1916 ensureRenderTarget();
1917
1918 if (isValidLevel(level))
1919 {
1920 updateStorageLevel(level);
1921
1922 gl::Rectangle sourceRect;
1923 sourceRect.x = x;
1924 sourceRect.width = width;
1925 sourceRect.y = y;
1926 sourceRect.height = height;
1927
Jamie Madill856d9d42014-09-18 15:08:49 -04001928 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1929 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001930 }
1931 }
1932}
1933
Brandon Jonescef06ff2014-08-05 13:27:48 -07001934void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001935{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001936 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1937
Brandon Jones142ec422014-07-16 10:31:30 -07001938 deleteImages();
1939
1940 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1941 {
1942 GLsizei levelWidth = std::max(1, width >> level);
1943 GLsizei levelHeight = std::max(1, height >> level);
1944
1945 mLayerCounts[level] = (level < levels ? depth : 0);
1946
1947 if (mLayerCounts[level] > 0)
1948 {
1949 // Create new images for this level
1950 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1951
1952 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1953 {
1954 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1955 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1956 levelHeight, 1, true);
1957 }
1958 }
1959 }
1960
1961 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001962
1963 bool renderTarget = IsRenderTargetUsage(mUsage);
1964 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001965 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07001966}
1967
Brandon Jones6053a522014-07-25 16:22:09 -07001968void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001969{
Brandon Jones6053a522014-07-25 16:22:09 -07001970 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001971}
1972
Brandon Jones6053a522014-07-25 16:22:09 -07001973void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001974{
Brandon Jones6053a522014-07-25 16:22:09 -07001975 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001976}
1977
Brandon Jones6053a522014-07-25 16:22:09 -07001978
Brandon Jones142ec422014-07-16 10:31:30 -07001979void TextureD3D_2DArray::generateMipmaps()
1980{
1981 int baseWidth = getBaseLevelWidth();
1982 int baseHeight = getBaseLevelHeight();
1983 int baseDepth = getBaseLevelDepth();
1984 GLenum baseFormat = getBaseLevelInternalFormat();
1985
1986 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1987 int levelCount = mipLevels();
1988 for (int level = 1; level < levelCount; level++)
1989 {
1990 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1991 }
1992
1993 if (mTexStorage && mTexStorage->isRenderTarget())
1994 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001995 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001996
Brandon Jones142ec422014-07-16 10:31:30 -07001997 for (int level = 1; level < levelCount; level++)
1998 {
Brandon Jones142ec422014-07-16 10:31:30 -07001999 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2000 {
2001 mImageArray[level][layer]->markClean();
2002 }
2003 }
2004 }
2005 else
2006 {
2007 for (int level = 1; level < levelCount; level++)
2008 {
2009 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2010 {
2011 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2012 }
2013 }
2014 }
2015}
2016
Jamie Madillac7579c2014-09-17 16:59:33 -04002017unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002018{
Jamie Madillc4833262014-09-18 16:18:26 -04002019 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002020}
2021
Jamie Madillac7579c2014-09-17 16:59:33 -04002022RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002023{
2024 // ensure the underlying texture is created
2025 if (!ensureRenderTarget())
2026 {
2027 return NULL;
2028 }
2029
Jamie Madillac7579c2014-09-17 16:59:33 -04002030 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002031 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002032}
2033
2034void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2035{
2036 // Only initialize the first time this texture is used as a render target or shader resource
2037 if (mTexStorage)
2038 {
2039 return;
2040 }
2041
2042 // do not attempt to create storage for nonexistant data
2043 if (!isLevelComplete(0))
2044 {
2045 return;
2046 }
2047
2048 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2049
2050 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2051 ASSERT(mTexStorage);
2052
2053 // flush image data to the storage
2054 updateStorage();
2055}
2056
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002057TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002058{
2059 GLsizei width = getBaseLevelWidth();
2060 GLsizei height = getBaseLevelHeight();
2061 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002062 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002063
2064 ASSERT(width > 0 && height > 0 && depth > 0);
2065
2066 // use existing storage level count, when previously specified by TexStorage*D
2067 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2068
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002069 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002070}
2071
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002072void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002073{
2074 SafeDelete(mTexStorage);
2075 mTexStorage = newCompleteTexStorage;
2076 mDirtyImages = true;
2077
2078 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2079 ASSERT(!mTexStorage->isManaged());
2080}
2081
2082void TextureD3D_2DArray::updateStorage()
2083{
2084 ASSERT(mTexStorage != NULL);
2085 GLint storageLevels = mTexStorage->getLevelCount();
2086 for (int level = 0; level < storageLevels; level++)
2087 {
2088 if (isLevelComplete(level))
2089 {
2090 updateStorageLevel(level);
2091 }
2092 }
2093}
2094
2095bool TextureD3D_2DArray::ensureRenderTarget()
2096{
2097 initializeStorage(true);
2098
2099 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2100 {
2101 ASSERT(mTexStorage);
2102 if (!mTexStorage->isRenderTarget())
2103 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002104 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002105
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002106 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002107 {
2108 delete newRenderTargetStorage;
2109 return gl::error(GL_OUT_OF_MEMORY, false);
2110 }
2111
2112 setCompleteTexStorage(newRenderTargetStorage);
2113 }
2114 }
2115
2116 return (mTexStorage && mTexStorage->isRenderTarget());
2117}
2118
2119const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2120{
2121 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2122}
2123
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002124TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002125{
2126 return mTexStorage;
2127}
2128
2129bool TextureD3D_2DArray::isValidLevel(int level) const
2130{
2131 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2132}
2133
2134bool TextureD3D_2DArray::isLevelComplete(int level) const
2135{
2136 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2137
2138 if (isImmutable())
2139 {
2140 return true;
2141 }
2142
2143 GLsizei width = getBaseLevelWidth();
2144 GLsizei height = getBaseLevelHeight();
2145 GLsizei layers = getLayers(0);
2146
2147 if (width <= 0 || height <= 0 || layers <= 0)
2148 {
2149 return false;
2150 }
2151
2152 if (level == 0)
2153 {
2154 return true;
2155 }
2156
2157 if (getInternalFormat(level) != getInternalFormat(0))
2158 {
2159 return false;
2160 }
2161
2162 if (getWidth(level) != std::max(1, width >> level))
2163 {
2164 return false;
2165 }
2166
2167 if (getHeight(level) != std::max(1, height >> level))
2168 {
2169 return false;
2170 }
2171
2172 if (getLayers(level) != layers)
2173 {
2174 return false;
2175 }
2176
2177 return true;
2178}
2179
2180void TextureD3D_2DArray::updateStorageLevel(int level)
2181{
2182 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2183 ASSERT(isLevelComplete(level));
2184
2185 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2186 {
2187 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2188 if (mImageArray[level][layer]->isDirty())
2189 {
2190 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2191 }
2192 }
2193}
2194
2195void TextureD3D_2DArray::deleteImages()
2196{
2197 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2198 {
2199 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2200 {
2201 delete mImageArray[level][layer];
2202 }
2203 delete[] mImageArray[level];
2204 mImageArray[level] = NULL;
2205 mLayerCounts[level] = 0;
2206 }
2207}
2208
2209void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2210{
2211 // If there currently is a corresponding storage texture image, it has these parameters
2212 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2213 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2214 const int storageDepth = getLayers(0);
2215 const GLenum storageFormat = getBaseLevelInternalFormat();
2216
2217 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2218 {
2219 delete mImageArray[level][layer];
2220 }
2221 delete[] mImageArray[level];
2222 mImageArray[level] = NULL;
2223 mLayerCounts[level] = depth;
2224
2225 if (depth > 0)
2226 {
2227 mImageArray[level] = new ImageD3D*[depth]();
2228
2229 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2230 {
2231 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2232 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2233 }
2234 }
2235
2236 if (mTexStorage)
2237 {
2238 const int storageLevels = mTexStorage->getLevelCount();
2239
2240 if ((level >= storageLevels && storageLevels != 0) ||
2241 width != storageWidth ||
2242 height != storageHeight ||
2243 depth != storageDepth ||
2244 internalformat != storageFormat) // Discard mismatched storage
2245 {
2246 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2247 {
2248 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2249 {
2250 mImageArray[level][layer]->markDirty();
2251 }
2252 }
2253
2254 delete mTexStorage;
2255 mTexStorage = NULL;
2256 mDirtyImages = true;
2257 }
2258 }
2259}
2260
2261void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2262{
2263 if (isValidLevel(level) && layerTarget < getLayers(level))
2264 {
2265 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002266 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002267 {
2268 image->markClean();
2269 }
2270 }
2271}
2272
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002273gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2274{
2275 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2276}
2277
Brandon Jones78b1acd2014-07-15 15:33:07 -07002278}