blob: 447254e9227c343224686d110c0693ec0f948163 [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
Jamie Madillcb83dc12014-09-29 10:46:12 -0400747gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
748{
749 // "layer" does not apply to 2D Textures.
750 return gl::ImageIndex::Make2D(mip);
751}
752
Brandon Jones78b1acd2014-07-15 15:33:07 -0700753TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700754 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700755 mTexStorage(NULL)
756{
757 for (int i = 0; i < 6; i++)
758 {
759 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
760 {
761 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
762 }
763 }
764}
765
766TextureD3D_Cube::~TextureD3D_Cube()
767{
Austin Kinross69822602014-08-12 15:51:37 -0700768 // Delete the Images before the TextureStorage.
769 // Images might be relying on the TextureStorage for some of their data.
770 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -0700771 for (int i = 0; i < 6; i++)
772 {
773 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
774 {
775 SafeDelete(mImageArray[i][j]);
776 }
777 }
Austin Kinross69822602014-08-12 15:51:37 -0700778
779 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700780}
781
Brandon Jonescef06ff2014-08-05 13:27:48 -0700782Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700783{
784 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700785 ASSERT(layer < 6);
786 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700787}
788
Jamie Madillfeda4d22014-09-17 13:03:29 -0400789Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
790{
791 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
792 ASSERT(index.layerIndex < 6);
793 return mImageArray[index.layerIndex][index.mipIndex];
794}
795
Brandon Jonescef06ff2014-08-05 13:27:48 -0700796GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700797{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700798 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
799 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700800}
801
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700803{
804 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700805 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700806 else
807 return GL_NONE;
808}
809
Brandon Jonescef06ff2014-08-05 13:27:48 -0700810bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700811{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700812 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700813}
814
Brandon Jonescef06ff2014-08-05 13:27:48 -0700815void 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 -0700816{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817 ASSERT(depth == 1);
818
819 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400820 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700821
822 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
823
824 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
825}
826
Brandon Jonescef06ff2014-08-05 13:27:48 -0700827void 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 -0700828{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700829 ASSERT(depth == 1);
830
Brandon Jones0511e802014-07-14 16:27:26 -0700831 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700832 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
833
Brandon Jones0511e802014-07-14 16:27:26 -0700834 redefineImage(faceIndex, level, format, width, height);
835
836 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
837}
838
Brandon Jonescef06ff2014-08-05 13:27:48 -0700839void 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 -0700840{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700841 ASSERT(depth == 1 && zoffset == 0);
842
843 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
844
Jamie Madillfeda4d22014-09-17 13:03:29 -0400845 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
846 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700847 {
848 commitRect(faceIndex, level, xoffset, yoffset, width, height);
849 }
850}
851
Brandon Jonescef06ff2014-08-05 13:27:48 -0700852void 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 -0700853{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700854 ASSERT(depth == 1 && zoffset == 0);
855
856 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
857
Brandon Jones0511e802014-07-14 16:27:26 -0700858 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
859 {
860 commitRect(faceIndex, level, xoffset, yoffset, width, height);
861 }
862}
863
864void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
865{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700866 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400867 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
868
Brandon Jones0511e802014-07-14 16:27:26 -0700869 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
870
871 if (!mImageArray[faceIndex][level]->isRenderableFormat())
872 {
873 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
874 mDirtyImages = true;
875 }
876 else
877 {
878 ensureRenderTarget();
879 mImageArray[faceIndex][level]->markClean();
880
881 ASSERT(width == height);
882
883 if (width > 0 && isValidFaceLevel(faceIndex, level))
884 {
885 gl::Rectangle sourceRect;
886 sourceRect.x = x;
887 sourceRect.width = width;
888 sourceRect.y = y;
889 sourceRect.height = height;
890
Jamie Madill856d9d42014-09-18 15:08:49 -0400891 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700892 }
893 }
894}
895
896void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
897{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700898 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700899
900 // We can only make our texture storage to a render target if the level we're copying *to* is complete
901 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
902 // rely on the "getBaseLevel*" methods reliably otherwise.
903 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
904
905 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
906 {
907 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
908 mDirtyImages = true;
909 }
910 else
911 {
912 ensureRenderTarget();
913
914 if (isValidFaceLevel(faceIndex, level))
915 {
916 updateStorageFaceLevel(faceIndex, level);
917
918 gl::Rectangle sourceRect;
919 sourceRect.x = x;
920 sourceRect.width = width;
921 sourceRect.y = y;
922 sourceRect.height = height;
923
Jamie Madill856d9d42014-09-18 15:08:49 -0400924 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
925 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700926 }
927 }
928}
929
Brandon Jonescef06ff2014-08-05 13:27:48 -0700930void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700931{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700932 ASSERT(width == height);
933 ASSERT(depth == 1);
934
Brandon Jones0511e802014-07-14 16:27:26 -0700935 for (int level = 0; level < levels; level++)
936 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700937 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700938 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
939 {
940 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
941 }
942 }
943
944 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
945 {
946 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
947 {
948 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
949 }
950 }
951
952 mImmutable = true;
953
Jamie Madillc4833262014-09-18 16:18:26 -0400954 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400955 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
956 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -0700957}
958
Brandon Jones0511e802014-07-14 16:27:26 -0700959// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
960bool TextureD3D_Cube::isCubeComplete() const
961{
962 int baseWidth = getBaseLevelWidth();
963 int baseHeight = getBaseLevelHeight();
964 GLenum baseFormat = getBaseLevelInternalFormat();
965
966 if (baseWidth <= 0 || baseWidth != baseHeight)
967 {
968 return false;
969 }
970
971 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
972 {
973 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
974
975 if (faceBaseImage.getWidth() != baseWidth ||
976 faceBaseImage.getHeight() != baseHeight ||
977 faceBaseImage.getInternalFormat() != baseFormat )
978 {
979 return false;
980 }
981 }
982
983 return true;
984}
985
Brandon Jones6053a522014-07-25 16:22:09 -0700986void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
987{
988 UNREACHABLE();
989}
990
991void TextureD3D_Cube::releaseTexImage()
992{
993 UNREACHABLE();
994}
995
996
Brandon Jones0511e802014-07-14 16:27:26 -0700997void TextureD3D_Cube::generateMipmaps()
998{
999 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1000 int levelCount = mipLevels();
1001 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1002 {
1003 for (int level = 1; level < levelCount; level++)
1004 {
1005 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1006 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1007 }
1008 }
1009
1010 if (mTexStorage && mTexStorage->isRenderTarget())
1011 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001012 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001013
Brandon Jones0511e802014-07-14 16:27:26 -07001014 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1015 {
1016 for (int level = 1; level < levelCount; level++)
1017 {
Brandon Jones0511e802014-07-14 16:27:26 -07001018 mImageArray[faceIndex][level]->markClean();
1019 }
1020 }
1021 }
1022 else
1023 {
1024 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1025 {
1026 for (int level = 1; level < levelCount; level++)
1027 {
1028 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1029 }
1030 }
1031 }
1032}
1033
Jamie Madillac7579c2014-09-17 16:59:33 -04001034unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001035{
Jamie Madillc4833262014-09-18 16:18:26 -04001036 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001037}
1038
Jamie Madillac7579c2014-09-17 16:59:33 -04001039RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001040{
Jamie Madillac7579c2014-09-17 16:59:33 -04001041 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001042
1043 // ensure the underlying texture is created
1044 if (!ensureRenderTarget())
1045 {
1046 return NULL;
1047 }
1048
Jamie Madillac7579c2014-09-17 16:59:33 -04001049 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001050 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001051}
1052
Brandon Jones0511e802014-07-14 16:27:26 -07001053void TextureD3D_Cube::initializeStorage(bool renderTarget)
1054{
1055 // Only initialize the first time this texture is used as a render target or shader resource
1056 if (mTexStorage)
1057 {
1058 return;
1059 }
1060
1061 // do not attempt to create storage for nonexistant data
1062 if (!isFaceLevelComplete(0, 0))
1063 {
1064 return;
1065 }
1066
1067 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1068
1069 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1070 ASSERT(mTexStorage);
1071
1072 // flush image data to the storage
1073 updateStorage();
1074}
1075
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001076TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001077{
1078 GLsizei size = getBaseLevelWidth();
1079
1080 ASSERT(size > 0);
1081
1082 // use existing storage level count, when previously specified by TexStorage*D
1083 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1084
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001085 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001086}
1087
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001088void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001089{
1090 SafeDelete(mTexStorage);
1091 mTexStorage = newCompleteTexStorage;
1092
1093 if (mTexStorage && mTexStorage->isManaged())
1094 {
1095 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1096 {
1097 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1098 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001099 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001100 }
1101 }
1102 }
1103
1104 mDirtyImages = true;
1105}
1106
1107void TextureD3D_Cube::updateStorage()
1108{
1109 ASSERT(mTexStorage != NULL);
1110 GLint storageLevels = mTexStorage->getLevelCount();
1111 for (int face = 0; face < 6; face++)
1112 {
1113 for (int level = 0; level < storageLevels; level++)
1114 {
1115 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1116 {
1117 updateStorageFaceLevel(face, level);
1118 }
1119 }
1120 }
1121}
1122
1123bool TextureD3D_Cube::ensureRenderTarget()
1124{
1125 initializeStorage(true);
1126
1127 if (getBaseLevelWidth() > 0)
1128 {
1129 ASSERT(mTexStorage);
1130 if (!mTexStorage->isRenderTarget())
1131 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001132 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001133
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001134 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001135 {
1136 delete newRenderTargetStorage;
1137 return gl::error(GL_OUT_OF_MEMORY, false);
1138 }
1139
1140 setCompleteTexStorage(newRenderTargetStorage);
1141 }
1142 }
1143
1144 return (mTexStorage && mTexStorage->isRenderTarget());
1145}
1146
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001147TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001148{
1149 return mTexStorage;
1150}
1151
1152const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1153{
1154 // Note: if we are not cube-complete, there is no single base level image that can describe all
1155 // cube faces, so this method is only well-defined for a cube-complete base level.
1156 return mImageArray[0][0];
1157}
1158
Brandon Jones0511e802014-07-14 16:27:26 -07001159bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1160{
1161 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1162}
1163
Brandon Jones0511e802014-07-14 16:27:26 -07001164bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1165{
1166 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1167
1168 if (isImmutable())
1169 {
1170 return true;
1171 }
1172
1173 int baseSize = getBaseLevelWidth();
1174
1175 if (baseSize <= 0)
1176 {
1177 return false;
1178 }
1179
1180 // "isCubeComplete" checks for base level completeness and we must call that
1181 // to determine if any face at level 0 is complete. We omit that check here
1182 // to avoid re-checking cube-completeness for every face at level 0.
1183 if (level == 0)
1184 {
1185 return true;
1186 }
1187
1188 // Check that non-zero levels are consistent with the base level.
1189 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1190
1191 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1192 {
1193 return false;
1194 }
1195
1196 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1197 {
1198 return false;
1199 }
1200
1201 return true;
1202}
1203
1204void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1205{
1206 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1207 ImageD3D *image = mImageArray[faceIndex][level];
1208
1209 if (image->isDirty())
1210 {
1211 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1212 }
1213}
1214
1215void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1216{
1217 // If there currently is a corresponding storage texture image, it has these parameters
1218 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1219 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1220 const GLenum storageFormat = getBaseLevelInternalFormat();
1221
1222 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1223
1224 if (mTexStorage)
1225 {
1226 const int storageLevels = mTexStorage->getLevelCount();
1227
1228 if ((level >= storageLevels && storageLevels != 0) ||
1229 width != storageWidth ||
1230 height != storageHeight ||
1231 internalformat != storageFormat) // Discard mismatched storage
1232 {
1233 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1234 {
1235 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1236 {
1237 mImageArray[faceIndex][level]->markDirty();
1238 }
1239 }
1240
1241 SafeDelete(mTexStorage);
1242
1243 mDirtyImages = true;
1244 }
1245 }
1246}
1247
1248void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1249{
1250 if (isValidFaceLevel(faceIndex, level))
1251 {
1252 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001253 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001254 image->markClean();
1255 }
1256}
1257
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001258gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1259{
1260 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1261}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001262
Jamie Madillcb83dc12014-09-29 10:46:12 -04001263gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1264{
1265 // The "layer" of the image index corresponds to the cube face
1266 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1267}
1268
Brandon Jones78b1acd2014-07-15 15:33:07 -07001269TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001270 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001271 mTexStorage(NULL)
1272{
1273 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1274 {
1275 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1276 }
1277}
1278
1279TextureD3D_3D::~TextureD3D_3D()
1280{
Austin Kinross69822602014-08-12 15:51:37 -07001281 // Delete the Images before the TextureStorage.
1282 // Images might be relying on the TextureStorage for some of their data.
1283 // 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 -07001284 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1285 {
1286 delete mImageArray[i];
1287 }
Austin Kinross69822602014-08-12 15:51:37 -07001288
1289 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001290}
1291
Brandon Jonescef06ff2014-08-05 13:27:48 -07001292Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001293{
1294 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001295 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001296 return mImageArray[level];
1297}
1298
Jamie Madillfeda4d22014-09-17 13:03:29 -04001299Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1300{
1301 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001302 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001303 ASSERT(index.type == GL_TEXTURE_3D);
1304 return mImageArray[index.mipIndex];
1305}
1306
Brandon Jonescef06ff2014-08-05 13:27:48 -07001307GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001308{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001309 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1310 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001311}
1312
Brandon Jones78b1acd2014-07-15 15:33:07 -07001313GLsizei TextureD3D_3D::getWidth(GLint level) const
1314{
1315 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1316 return mImageArray[level]->getWidth();
1317 else
1318 return 0;
1319}
1320
1321GLsizei TextureD3D_3D::getHeight(GLint level) const
1322{
1323 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1324 return mImageArray[level]->getHeight();
1325 else
1326 return 0;
1327}
1328
1329GLsizei TextureD3D_3D::getDepth(GLint level) const
1330{
1331 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1332 return mImageArray[level]->getDepth();
1333 else
1334 return 0;
1335}
1336
1337GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1338{
1339 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1340 return mImageArray[level]->getInternalFormat();
1341 else
1342 return GL_NONE;
1343}
1344
1345bool TextureD3D_3D::isDepth(GLint level) const
1346{
Geoff Lang5d601382014-07-22 15:14:06 -04001347 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001348}
1349
Brandon Jonescef06ff2014-08-05 13:27:48 -07001350void 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 -07001351{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001352 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001353 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1354
Brandon Jones78b1acd2014-07-15 15:33:07 -07001355 redefineImage(level, sizedInternalFormat, width, height, depth);
1356
1357 bool fastUnpacked = false;
1358
1359 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1360 if (isFastUnpackable(unpack, sizedInternalFormat))
1361 {
1362 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001363 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1364 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001365 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1366
1367 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1368 {
1369 // Ensure we don't overwrite our newly initialized data
1370 mImageArray[level]->markClean();
1371
1372 fastUnpacked = true;
1373 }
1374 }
1375
1376 if (!fastUnpacked)
1377 {
1378 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1379 }
1380}
1381
Brandon Jonescef06ff2014-08-05 13:27:48 -07001382void 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 -07001383{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001384 ASSERT(target == GL_TEXTURE_3D);
1385
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1387 redefineImage(level, format, width, height, depth);
1388
1389 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1390}
1391
Brandon Jonescef06ff2014-08-05 13:27:48 -07001392void 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 -07001393{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001394 ASSERT(target == GL_TEXTURE_3D);
1395
Brandon Jones78b1acd2014-07-15 15:33:07 -07001396 bool fastUnpacked = false;
1397
Jamie Madillac7579c2014-09-17 16:59:33 -04001398 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1399
Brandon Jones78b1acd2014-07-15 15:33:07 -07001400 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1401 if (isFastUnpackable(unpack, getInternalFormat(level)))
1402 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001403 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001404 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1405
1406 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1407 {
1408 // Ensure we don't overwrite our newly initialized data
1409 mImageArray[level]->markClean();
1410
1411 fastUnpacked = true;
1412 }
1413 }
1414
Jamie Madillfeda4d22014-09-17 13:03:29 -04001415 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001416 {
1417 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1418 }
1419}
1420
Brandon Jonescef06ff2014-08-05 13:27:48 -07001421void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001422{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001423 ASSERT(target == GL_TEXTURE_3D);
1424
Brandon Jones78b1acd2014-07-15 15:33:07 -07001425 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1426 {
1427 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1428 }
1429}
1430
Brandon Jonescef06ff2014-08-05 13:27:48 -07001431void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1432{
1433 UNIMPLEMENTED();
1434}
1435
Brandon Jones78b1acd2014-07-15 15:33:07 -07001436void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1437{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001438 ASSERT(target == GL_TEXTURE_3D);
1439
Brandon Jones78b1acd2014-07-15 15:33:07 -07001440 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1441 // the current level we're copying to is defined (with appropriate format, width & height)
1442 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1443
1444 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1445 {
1446 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1447 mDirtyImages = true;
1448 }
1449 else
1450 {
1451 ensureRenderTarget();
1452
1453 if (isValidLevel(level))
1454 {
1455 updateStorageLevel(level);
1456
1457 gl::Rectangle sourceRect;
1458 sourceRect.x = x;
1459 sourceRect.width = width;
1460 sourceRect.y = y;
1461 sourceRect.height = height;
1462
Jamie Madill856d9d42014-09-18 15:08:49 -04001463 mRenderer->copyImage3D(source, sourceRect,
1464 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1465 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001466 }
1467 }
1468}
1469
Brandon Jonescef06ff2014-08-05 13:27:48 -07001470void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001472 ASSERT(target == GL_TEXTURE_3D);
1473
Brandon Jones78b1acd2014-07-15 15:33:07 -07001474 for (int level = 0; level < levels; level++)
1475 {
1476 GLsizei levelWidth = std::max(1, width >> level);
1477 GLsizei levelHeight = std::max(1, height >> level);
1478 GLsizei levelDepth = std::max(1, depth >> level);
1479 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1480 }
1481
1482 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1483 {
1484 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1485 }
1486
1487 mImmutable = true;
1488
Jamie Madillc4833262014-09-18 16:18:26 -04001489 bool renderTarget = IsRenderTargetUsage(mUsage);
1490 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001491 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001492}
1493
Brandon Jones6053a522014-07-25 16:22:09 -07001494void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495{
Brandon Jones6053a522014-07-25 16:22:09 -07001496 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001497}
1498
Brandon Jones6053a522014-07-25 16:22:09 -07001499void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500{
Brandon Jones6053a522014-07-25 16:22:09 -07001501 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001502}
1503
Brandon Jones6053a522014-07-25 16:22:09 -07001504
Brandon Jones78b1acd2014-07-15 15:33:07 -07001505void TextureD3D_3D::generateMipmaps()
1506{
1507 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1508 int levelCount = mipLevels();
1509 for (int level = 1; level < levelCount; level++)
1510 {
1511 redefineImage(level, getBaseLevelInternalFormat(),
1512 std::max(getBaseLevelWidth() >> level, 1),
1513 std::max(getBaseLevelHeight() >> level, 1),
1514 std::max(getBaseLevelDepth() >> level, 1));
1515 }
1516
1517 if (mTexStorage && mTexStorage->isRenderTarget())
1518 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001519 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04001520
Brandon Jones78b1acd2014-07-15 15:33:07 -07001521 for (int level = 1; level < levelCount; level++)
1522 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523 mImageArray[level]->markClean();
1524 }
1525 }
1526 else
1527 {
1528 for (int level = 1; level < levelCount; level++)
1529 {
1530 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1531 }
1532 }
1533}
1534
Jamie Madillac7579c2014-09-17 16:59:33 -04001535unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001536{
Jamie Madillc4833262014-09-18 16:18:26 -04001537 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001538}
1539
Jamie Madillac7579c2014-09-17 16:59:33 -04001540RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001541{
1542 // ensure the underlying texture is created
1543 if (!ensureRenderTarget())
1544 {
1545 return NULL;
1546 }
1547
Jamie Madillac7579c2014-09-17 16:59:33 -04001548 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001549 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001550 updateStorage();
1551 }
1552 else
1553 {
1554 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001555 }
1556
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001557 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001558}
1559
1560void TextureD3D_3D::initializeStorage(bool renderTarget)
1561{
1562 // Only initialize the first time this texture is used as a render target or shader resource
1563 if (mTexStorage)
1564 {
1565 return;
1566 }
1567
1568 // do not attempt to create storage for nonexistant data
1569 if (!isLevelComplete(0))
1570 {
1571 return;
1572 }
1573
1574 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1575
1576 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1577 ASSERT(mTexStorage);
1578
1579 // flush image data to the storage
1580 updateStorage();
1581}
1582
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001583TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001584{
1585 GLsizei width = getBaseLevelWidth();
1586 GLsizei height = getBaseLevelHeight();
1587 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001588 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001589
1590 ASSERT(width > 0 && height > 0 && depth > 0);
1591
1592 // use existing storage level count, when previously specified by TexStorage*D
1593 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1594
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001595 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001596}
1597
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001598void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001599{
1600 SafeDelete(mTexStorage);
1601 mTexStorage = newCompleteTexStorage;
1602 mDirtyImages = true;
1603
1604 // We do not support managed 3D storage, as that is D3D9/ES2-only
1605 ASSERT(!mTexStorage->isManaged());
1606}
1607
1608void TextureD3D_3D::updateStorage()
1609{
1610 ASSERT(mTexStorage != NULL);
1611 GLint storageLevels = mTexStorage->getLevelCount();
1612 for (int level = 0; level < storageLevels; level++)
1613 {
1614 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1615 {
1616 updateStorageLevel(level);
1617 }
1618 }
1619}
1620
1621bool TextureD3D_3D::ensureRenderTarget()
1622{
1623 initializeStorage(true);
1624
1625 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1626 {
1627 ASSERT(mTexStorage);
1628 if (!mTexStorage->isRenderTarget())
1629 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001630 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001631
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001632 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001633 {
1634 delete newRenderTargetStorage;
1635 return gl::error(GL_OUT_OF_MEMORY, false);
1636 }
1637
1638 setCompleteTexStorage(newRenderTargetStorage);
1639 }
1640 }
1641
1642 return (mTexStorage && mTexStorage->isRenderTarget());
1643}
1644
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001645TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001646{
1647 return mTexStorage;
1648}
1649
1650const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1651{
1652 return mImageArray[0];
1653}
1654
1655bool TextureD3D_3D::isValidLevel(int level) const
1656{
1657 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1658}
1659
1660bool TextureD3D_3D::isLevelComplete(int level) const
1661{
1662 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1663
1664 if (isImmutable())
1665 {
1666 return true;
1667 }
1668
1669 GLsizei width = getBaseLevelWidth();
1670 GLsizei height = getBaseLevelHeight();
1671 GLsizei depth = getBaseLevelDepth();
1672
1673 if (width <= 0 || height <= 0 || depth <= 0)
1674 {
1675 return false;
1676 }
1677
1678 if (level == 0)
1679 {
1680 return true;
1681 }
1682
1683 ImageD3D *levelImage = mImageArray[level];
1684
1685 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1686 {
1687 return false;
1688 }
1689
1690 if (levelImage->getWidth() != std::max(1, width >> level))
1691 {
1692 return false;
1693 }
1694
1695 if (levelImage->getHeight() != std::max(1, height >> level))
1696 {
1697 return false;
1698 }
1699
1700 if (levelImage->getDepth() != std::max(1, depth >> level))
1701 {
1702 return false;
1703 }
1704
1705 return true;
1706}
1707
1708void TextureD3D_3D::updateStorageLevel(int level)
1709{
1710 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1711 ASSERT(isLevelComplete(level));
1712
1713 if (mImageArray[level]->isDirty())
1714 {
1715 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1716 }
1717}
1718
1719void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1720{
1721 // If there currently is a corresponding storage texture image, it has these parameters
1722 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1723 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1724 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1725 const GLenum storageFormat = getBaseLevelInternalFormat();
1726
1727 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1728
1729 if (mTexStorage)
1730 {
1731 const int storageLevels = mTexStorage->getLevelCount();
1732
1733 if ((level >= storageLevels && storageLevels != 0) ||
1734 width != storageWidth ||
1735 height != storageHeight ||
1736 depth != storageDepth ||
1737 internalformat != storageFormat) // Discard mismatched storage
1738 {
1739 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1740 {
1741 mImageArray[i]->markDirty();
1742 }
1743
1744 SafeDelete(mTexStorage);
1745 mDirtyImages = true;
1746 }
1747 }
1748}
1749
1750void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1751{
1752 if (isValidLevel(level))
1753 {
1754 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001755 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001756 {
1757 image->markClean();
1758 }
1759 }
1760}
1761
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001762gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1763{
1764 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1765 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1766}
Brandon Jones142ec422014-07-16 10:31:30 -07001767
Jamie Madillcb83dc12014-09-29 10:46:12 -04001768gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1769{
1770 // The "layer" here does not apply to 3D images. We use one Image per mip.
1771 return gl::ImageIndex::Make3D(mip);
1772}
1773
Brandon Jones142ec422014-07-16 10:31:30 -07001774TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001775 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001776 mTexStorage(NULL)
1777{
1778 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1779 {
1780 mLayerCounts[level] = 0;
1781 mImageArray[level] = NULL;
1782 }
1783}
1784
1785TextureD3D_2DArray::~TextureD3D_2DArray()
1786{
Austin Kinross69822602014-08-12 15:51:37 -07001787 // Delete the Images before the TextureStorage.
1788 // Images might be relying on the TextureStorage for some of their data.
1789 // 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 -07001790 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001791 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001792}
1793
Brandon Jones142ec422014-07-16 10:31:30 -07001794Image *TextureD3D_2DArray::getImage(int level, int layer) const
1795{
1796 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1797 ASSERT(layer < mLayerCounts[level]);
1798 return mImageArray[level][layer];
1799}
1800
Jamie Madillfeda4d22014-09-17 13:03:29 -04001801Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1802{
1803 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1804 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1805 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1806 return mImageArray[index.mipIndex][index.layerIndex];
1807}
1808
Brandon Jones142ec422014-07-16 10:31:30 -07001809GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1810{
1811 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1812 return mLayerCounts[level];
1813}
1814
Brandon Jones142ec422014-07-16 10:31:30 -07001815GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1816{
1817 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1818}
1819
1820GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1821{
1822 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1823}
1824
1825GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1826{
1827 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1828}
1829
1830GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1831{
1832 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1833}
1834
1835bool TextureD3D_2DArray::isDepth(GLint level) const
1836{
Geoff Lang5d601382014-07-22 15:14:06 -04001837 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001838}
1839
Brandon Jonescef06ff2014-08-05 13:27:48 -07001840void 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 -07001841{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001842 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1843
Geoff Lang5d601382014-07-22 15:14:06 -04001844 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1845
Brandon Jones142ec422014-07-16 10:31:30 -07001846 redefineImage(level, sizedInternalFormat, width, height, depth);
1847
Geoff Lang5d601382014-07-22 15:14:06 -04001848 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1849 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001850
1851 for (int i = 0; i < depth; i++)
1852 {
1853 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1854 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1855 }
1856}
1857
Brandon Jonescef06ff2014-08-05 13:27:48 -07001858void 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 -07001859{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001860 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1861
Brandon Jones142ec422014-07-16 10:31:30 -07001862 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1863 redefineImage(level, format, width, height, depth);
1864
Geoff Lang5d601382014-07-22 15:14:06 -04001865 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1866 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001867
1868 for (int i = 0; i < depth; i++)
1869 {
1870 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1871 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1872 }
1873}
1874
Brandon Jonescef06ff2014-08-05 13:27:48 -07001875void 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 -07001876{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001877 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1878
Geoff Lang5d601382014-07-22 15:14:06 -04001879 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1880 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001881
1882 for (int i = 0; i < depth; i++)
1883 {
1884 int layer = zoffset + i;
1885 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1886
Jamie Madillfeda4d22014-09-17 13:03:29 -04001887 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1888 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001889 {
1890 commitRect(level, xoffset, yoffset, layer, width, height);
1891 }
1892 }
1893}
1894
Brandon Jonescef06ff2014-08-05 13:27:48 -07001895void 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 -07001896{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001897 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1898
Geoff Lang5d601382014-07-22 15:14:06 -04001899 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1900 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001901
1902 for (int i = 0; i < depth; i++)
1903 {
1904 int layer = zoffset + i;
1905 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1906
1907 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1908 {
1909 commitRect(level, xoffset, yoffset, layer, width, height);
1910 }
1911 }
1912}
1913
Brandon Jonescef06ff2014-08-05 13:27:48 -07001914void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1915{
1916 UNIMPLEMENTED();
1917}
1918
Brandon Jones142ec422014-07-16 10:31:30 -07001919void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1920{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001921 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1922
Brandon Jones142ec422014-07-16 10:31:30 -07001923 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1924 // the current level we're copying to is defined (with appropriate format, width & height)
1925 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1926
1927 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1928 {
1929 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1930 mDirtyImages = true;
1931 }
1932 else
1933 {
1934 ensureRenderTarget();
1935
1936 if (isValidLevel(level))
1937 {
1938 updateStorageLevel(level);
1939
1940 gl::Rectangle sourceRect;
1941 sourceRect.x = x;
1942 sourceRect.width = width;
1943 sourceRect.y = y;
1944 sourceRect.height = height;
1945
Jamie Madill856d9d42014-09-18 15:08:49 -04001946 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1947 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001948 }
1949 }
1950}
1951
Brandon Jonescef06ff2014-08-05 13:27:48 -07001952void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001953{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001954 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1955
Brandon Jones142ec422014-07-16 10:31:30 -07001956 deleteImages();
1957
1958 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1959 {
1960 GLsizei levelWidth = std::max(1, width >> level);
1961 GLsizei levelHeight = std::max(1, height >> level);
1962
1963 mLayerCounts[level] = (level < levels ? depth : 0);
1964
1965 if (mLayerCounts[level] > 0)
1966 {
1967 // Create new images for this level
1968 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1969
1970 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1971 {
1972 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1973 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1974 levelHeight, 1, true);
1975 }
1976 }
1977 }
1978
1979 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001980
1981 bool renderTarget = IsRenderTargetUsage(mUsage);
1982 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001983 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07001984}
1985
Brandon Jones6053a522014-07-25 16:22:09 -07001986void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001987{
Brandon Jones6053a522014-07-25 16:22:09 -07001988 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001989}
1990
Brandon Jones6053a522014-07-25 16:22:09 -07001991void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001992{
Brandon Jones6053a522014-07-25 16:22:09 -07001993 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001994}
1995
Brandon Jones6053a522014-07-25 16:22:09 -07001996
Brandon Jones142ec422014-07-16 10:31:30 -07001997void TextureD3D_2DArray::generateMipmaps()
1998{
1999 int baseWidth = getBaseLevelWidth();
2000 int baseHeight = getBaseLevelHeight();
2001 int baseDepth = getBaseLevelDepth();
2002 GLenum baseFormat = getBaseLevelInternalFormat();
2003
2004 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2005 int levelCount = mipLevels();
2006 for (int level = 1; level < levelCount; level++)
2007 {
2008 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2009 }
2010
2011 if (mTexStorage && mTexStorage->isRenderTarget())
2012 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002013 mTexStorage->generateMipmaps();
Jamie Madill5e48c032014-09-18 15:08:47 -04002014
Brandon Jones142ec422014-07-16 10:31:30 -07002015 for (int level = 1; level < levelCount; level++)
2016 {
Brandon Jones142ec422014-07-16 10:31:30 -07002017 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2018 {
2019 mImageArray[level][layer]->markClean();
2020 }
2021 }
2022 }
2023 else
2024 {
2025 for (int level = 1; level < levelCount; level++)
2026 {
2027 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2028 {
2029 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2030 }
2031 }
2032 }
2033}
2034
Jamie Madillac7579c2014-09-17 16:59:33 -04002035unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002036{
Jamie Madillc4833262014-09-18 16:18:26 -04002037 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002038}
2039
Jamie Madillac7579c2014-09-17 16:59:33 -04002040RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002041{
2042 // ensure the underlying texture is created
2043 if (!ensureRenderTarget())
2044 {
2045 return NULL;
2046 }
2047
Jamie Madillac7579c2014-09-17 16:59:33 -04002048 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002049 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002050}
2051
2052void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2053{
2054 // Only initialize the first time this texture is used as a render target or shader resource
2055 if (mTexStorage)
2056 {
2057 return;
2058 }
2059
2060 // do not attempt to create storage for nonexistant data
2061 if (!isLevelComplete(0))
2062 {
2063 return;
2064 }
2065
2066 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2067
2068 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2069 ASSERT(mTexStorage);
2070
2071 // flush image data to the storage
2072 updateStorage();
2073}
2074
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002075TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002076{
2077 GLsizei width = getBaseLevelWidth();
2078 GLsizei height = getBaseLevelHeight();
2079 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002080 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002081
2082 ASSERT(width > 0 && height > 0 && depth > 0);
2083
2084 // use existing storage level count, when previously specified by TexStorage*D
2085 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2086
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002087 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002088}
2089
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002090void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002091{
2092 SafeDelete(mTexStorage);
2093 mTexStorage = newCompleteTexStorage;
2094 mDirtyImages = true;
2095
2096 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2097 ASSERT(!mTexStorage->isManaged());
2098}
2099
2100void TextureD3D_2DArray::updateStorage()
2101{
2102 ASSERT(mTexStorage != NULL);
2103 GLint storageLevels = mTexStorage->getLevelCount();
2104 for (int level = 0; level < storageLevels; level++)
2105 {
2106 if (isLevelComplete(level))
2107 {
2108 updateStorageLevel(level);
2109 }
2110 }
2111}
2112
2113bool TextureD3D_2DArray::ensureRenderTarget()
2114{
2115 initializeStorage(true);
2116
2117 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2118 {
2119 ASSERT(mTexStorage);
2120 if (!mTexStorage->isRenderTarget())
2121 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002122 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002123
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002124 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002125 {
2126 delete newRenderTargetStorage;
2127 return gl::error(GL_OUT_OF_MEMORY, false);
2128 }
2129
2130 setCompleteTexStorage(newRenderTargetStorage);
2131 }
2132 }
2133
2134 return (mTexStorage && mTexStorage->isRenderTarget());
2135}
2136
2137const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2138{
2139 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2140}
2141
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002142TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002143{
2144 return mTexStorage;
2145}
2146
2147bool TextureD3D_2DArray::isValidLevel(int level) const
2148{
2149 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2150}
2151
2152bool TextureD3D_2DArray::isLevelComplete(int level) const
2153{
2154 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2155
2156 if (isImmutable())
2157 {
2158 return true;
2159 }
2160
2161 GLsizei width = getBaseLevelWidth();
2162 GLsizei height = getBaseLevelHeight();
2163 GLsizei layers = getLayers(0);
2164
2165 if (width <= 0 || height <= 0 || layers <= 0)
2166 {
2167 return false;
2168 }
2169
2170 if (level == 0)
2171 {
2172 return true;
2173 }
2174
2175 if (getInternalFormat(level) != getInternalFormat(0))
2176 {
2177 return false;
2178 }
2179
2180 if (getWidth(level) != std::max(1, width >> level))
2181 {
2182 return false;
2183 }
2184
2185 if (getHeight(level) != std::max(1, height >> level))
2186 {
2187 return false;
2188 }
2189
2190 if (getLayers(level) != layers)
2191 {
2192 return false;
2193 }
2194
2195 return true;
2196}
2197
2198void TextureD3D_2DArray::updateStorageLevel(int level)
2199{
2200 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2201 ASSERT(isLevelComplete(level));
2202
2203 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2204 {
2205 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2206 if (mImageArray[level][layer]->isDirty())
2207 {
2208 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2209 }
2210 }
2211}
2212
2213void TextureD3D_2DArray::deleteImages()
2214{
2215 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
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] = 0;
2224 }
2225}
2226
2227void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2228{
2229 // If there currently is a corresponding storage texture image, it has these parameters
2230 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2231 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2232 const int storageDepth = getLayers(0);
2233 const GLenum storageFormat = getBaseLevelInternalFormat();
2234
2235 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2236 {
2237 delete mImageArray[level][layer];
2238 }
2239 delete[] mImageArray[level];
2240 mImageArray[level] = NULL;
2241 mLayerCounts[level] = depth;
2242
2243 if (depth > 0)
2244 {
2245 mImageArray[level] = new ImageD3D*[depth]();
2246
2247 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2248 {
2249 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2250 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2251 }
2252 }
2253
2254 if (mTexStorage)
2255 {
2256 const int storageLevels = mTexStorage->getLevelCount();
2257
2258 if ((level >= storageLevels && storageLevels != 0) ||
2259 width != storageWidth ||
2260 height != storageHeight ||
2261 depth != storageDepth ||
2262 internalformat != storageFormat) // Discard mismatched storage
2263 {
2264 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2265 {
2266 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2267 {
2268 mImageArray[level][layer]->markDirty();
2269 }
2270 }
2271
2272 delete mTexStorage;
2273 mTexStorage = NULL;
2274 mDirtyImages = true;
2275 }
2276 }
2277}
2278
2279void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2280{
2281 if (isValidLevel(level) && layerTarget < getLayers(level))
2282 {
2283 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002284 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002285 {
2286 image->markClean();
2287 }
2288 }
2289}
2290
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002291gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2292{
2293 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2294}
2295
Jamie Madillcb83dc12014-09-29 10:46:12 -04002296gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2297{
2298 return gl::ImageIndex::Make2DArray(mip, layer);
2299}
2300
Brandon Jones78b1acd2014-07-15 15:33:07 -07002301}