blob: b68c7fadda28ab101dacd7bc17bb734e9f5a8400 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Brandon Jonesf47bebc2014-07-09 14:28:42 -070029bool IsRenderTargetUsage(GLenum usage)
30{
31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
32}
33
Brandon Jones78b1acd2014-07-15 15:33:07 -070034TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070035 : mRenderer(renderer),
36 mUsage(GL_NONE),
37 mDirtyImages(true),
38 mImmutable(false)
39{
40}
41
42TextureD3D::~TextureD3D()
43{
44}
45
Brandon Jones6053a522014-07-25 16:22:09 -070046TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
47{
48 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
49 return static_cast<TextureD3D*>(texture);
50}
51
52TextureStorageInterface *TextureD3D::getNativeTexture()
53{
54 // ensure the underlying texture is created
55 initializeStorage(false);
56
57 TextureStorageInterface *storage = getBaseLevelStorage();
58 if (storage)
59 {
60 updateStorage();
61 }
62
63 return storage;
64}
65
Brandon Jonesf47bebc2014-07-09 14:28:42 -070066GLint TextureD3D::getBaseLevelWidth() const
67{
Brandon Jones78b1acd2014-07-15 15:33:07 -070068 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 return (baseImage ? baseImage->getWidth() : 0);
70}
71
72GLint TextureD3D::getBaseLevelHeight() const
73{
Brandon Jones78b1acd2014-07-15 15:33:07 -070074 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075 return (baseImage ? baseImage->getHeight() : 0);
76}
77
78GLint TextureD3D::getBaseLevelDepth() const
79{
Brandon Jones78b1acd2014-07-15 15:33:07 -070080 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070081 return (baseImage ? baseImage->getDepth() : 0);
82}
83
84// Note: "base level image" is loosely defined to be any image from the base level,
85// where in the base of 2D array textures and cube maps there are several. Don't use
86// the base level image for anything except querying texture format and size.
87GLenum TextureD3D::getBaseLevelInternalFormat() const
88{
Brandon Jones78b1acd2014-07-15 15:33:07 -070089 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070090 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
91}
92
Brandon Jones78b1acd2014-07-15 15:33:07 -070093void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
95 // No-op
96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
97 {
98 return;
99 }
100
101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
103 const void *pixelData = pixels;
104
105 if (unpack.pixelBuffer.id() != 0)
106 {
107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
111 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
112 const void *bufferData = pixelBuffer->getImplementation()->getData();
113 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
114 }
115
116 if (pixelData != NULL)
117 {
118 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 mDirtyImages = true;
120 }
121}
122
123bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillfeda4d22014-09-17 13:03:29 -0400124 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700125{
126 const void *pixelData = pixels;
127
128 // CPU readback & copy where direct GPU copy is not supported
129 if (unpack.pixelBuffer.id() != 0)
130 {
131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
132 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
134 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
135 const void *bufferData = pixelBuffer->getImplementation()->getData();
136 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
137 }
138
139 if (pixelData != NULL)
140 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400141 Image *image = getImage(index);
142 ASSERT(image);
143
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
145 mDirtyImages = true;
146 }
147
148 return true;
149}
150
Brandon Jones78b1acd2014-07-15 15:33:07 -0700151void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152{
153 if (pixels != NULL)
154 {
155 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
156 mDirtyImages = true;
157 }
158}
159
160bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700161 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162{
163 if (pixels != NULL)
164 {
165 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
166 mDirtyImages = true;
167 }
168
169 return true;
170}
171
172bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
173{
174 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
175}
176
177bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700178 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700179{
180 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
181 {
182 return true;
183 }
184
185 // In order to perform the fast copy through the shader, we must have the right format, and be able
186 // to create a render target.
187 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
188
189 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
190
191 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
192}
193
194GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
195{
196 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
197 {
198 // Maximum number of levels
199 return gl::log2(std::max(std::max(width, height), depth)) + 1;
200 }
201 else
202 {
203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
204 return 1;
205 }
206}
207
208int TextureD3D::mipLevels() const
209{
210 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
211}
212
213
Brandon Jones78b1acd2014-07-15 15:33:07 -0700214TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700215 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700216 mTexStorage(NULL)
217{
218 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
219 {
220 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
221 }
222}
223
224TextureD3D_2D::~TextureD3D_2D()
225{
Austin Kinross69822602014-08-12 15:51:37 -0700226 // Delete the Images before the TextureStorage.
227 // Images might be relying on the TextureStorage for some of their data.
228 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700229 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
230 {
231 delete mImageArray[i];
232 }
Austin Kinross69822602014-08-12 15:51:37 -0700233
234 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700235}
236
Brandon Jonescef06ff2014-08-05 13:27:48 -0700237Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238{
239 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700240 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700241 return mImageArray[level];
242}
243
Jamie Madillfeda4d22014-09-17 13:03:29 -0400244Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
245{
246 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400247 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400248 ASSERT(index.type == GL_TEXTURE_2D);
249 return mImageArray[index.mipIndex];
250}
251
Brandon Jonescef06ff2014-08-05 13:27:48 -0700252GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700253{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700254 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
255 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700256}
257
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258GLsizei TextureD3D_2D::getWidth(GLint level) const
259{
260 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
261 return mImageArray[level]->getWidth();
262 else
263 return 0;
264}
265
266GLsizei TextureD3D_2D::getHeight(GLint level) const
267{
268 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
269 return mImageArray[level]->getHeight();
270 else
271 return 0;
272}
273
274GLenum TextureD3D_2D::getInternalFormat(GLint level) const
275{
276 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
277 return mImageArray[level]->getInternalFormat();
278 else
279 return GL_NONE;
280}
281
282GLenum TextureD3D_2D::getActualFormat(GLint level) const
283{
284 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
285 return mImageArray[level]->getActualFormat();
286 else
287 return GL_NONE;
288}
289
290bool TextureD3D_2D::isDepth(GLint level) const
291{
Geoff Lang5d601382014-07-22 15:14:06 -0400292 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700293}
294
Brandon Jonescef06ff2014-08-05 13:27:48 -0700295void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700296{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700297 ASSERT(target == GL_TEXTURE_2D && depth == 1);
298
Geoff Lang5d601382014-07-22 15:14:06 -0400299 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
300
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700301 bool fastUnpacked = false;
302
Brandon Jonescef06ff2014-08-05 13:27:48 -0700303 redefineImage(level, sizedInternalFormat, width, height);
304
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700305 // Attempt a fast gpu copy of the pixel data to the surface
306 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
307 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400308 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
309
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700310 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400311 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700312 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
313
314 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
315 {
316 // Ensure we don't overwrite our newly initialized data
317 mImageArray[level]->markClean();
318
319 fastUnpacked = true;
320 }
321 }
322
323 if (!fastUnpacked)
324 {
325 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
326 }
327}
328
Brandon Jonescef06ff2014-08-05 13:27:48 -0700329void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700330{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700331 ASSERT(target == GL_TEXTURE_2D && depth == 1);
332
333 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
334 redefineImage(level, format, width, height);
335
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700336 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
337}
338
Brandon Jonescef06ff2014-08-05 13:27:48 -0700339void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700340{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700341 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
342
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700343 bool fastUnpacked = false;
344
Jamie Madillac7579c2014-09-17 16:59:33 -0400345 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700346 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
347 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400348 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700349 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
350
351 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
352 {
353 // Ensure we don't overwrite our newly initialized data
354 mImageArray[level]->markClean();
355
356 fastUnpacked = true;
357 }
358 }
359
Jamie Madillfeda4d22014-09-17 13:03:29 -0400360 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700361 {
362 commitRect(level, xoffset, yoffset, width, height);
363 }
364}
365
Brandon Jonescef06ff2014-08-05 13:27:48 -0700366void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700367{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700368 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
369
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
371 {
372 commitRect(level, xoffset, yoffset, width, height);
373 }
374}
375
Brandon Jonescef06ff2014-08-05 13:27:48 -0700376void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700377{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700378 ASSERT(target == GL_TEXTURE_2D);
379
380 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
381 redefineImage(level, sizedInternalFormat, width, height);
382
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700383 if (!mImageArray[level]->isRenderableFormat())
384 {
385 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
386 mDirtyImages = true;
387 }
388 else
389 {
390 ensureRenderTarget();
391 mImageArray[level]->markClean();
392
393 if (width != 0 && height != 0 && isValidLevel(level))
394 {
395 gl::Rectangle sourceRect;
396 sourceRect.x = x;
397 sourceRect.width = width;
398 sourceRect.y = y;
399 sourceRect.height = height;
400
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 Madill856d9d42014-09-18 15:08:49 -0400460 setCompleteTexStorage(new TextureStorageInterface(storage, 1));
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 Madill856d9d42014-09-18 15:08:49 -0400473 TextureStorage *storage = mRenderer->createTextureStorage2D(surface->getSwapChain());
474 mTexStorage = new TextureStorageInterface(storage, 1);
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 Madill5e48c032014-09-18 15:08:47 -0400505 mTexStorage->getStorageInstance()->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);
537 return mTexStorage->getStorageInstance()->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 Madill856d9d42014-09-18 15:08:49 -0400613TextureStorageInterface *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 Madillc4833262014-09-18 16:18:26 -0400624 TextureStorage *storageInstance = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -0400625 return new TextureStorageInterface(storageInstance, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626}
627
Jamie Madill856d9d42014-09-18 15:08:49 -0400628void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700629{
630 SafeDelete(mTexStorage);
631 mTexStorage = newCompleteTexStorage;
632
633 if (mTexStorage && mTexStorage->isManaged())
634 {
635 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
636 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400637 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638 }
639 }
640
641 mDirtyImages = true;
642}
643
644void TextureD3D_2D::updateStorage()
645{
646 ASSERT(mTexStorage != NULL);
647 GLint storageLevels = mTexStorage->getLevelCount();
648 for (int level = 0; level < storageLevels; level++)
649 {
650 if (mImageArray[level]->isDirty() && isLevelComplete(level))
651 {
652 updateStorageLevel(level);
653 }
654 }
655}
656
657bool TextureD3D_2D::ensureRenderTarget()
658{
659 initializeStorage(true);
660
661 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
662 {
663 ASSERT(mTexStorage);
664 if (!mTexStorage->isRenderTarget())
665 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400666 TextureStorageInterface *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667
Jamie Madill856d9d42014-09-18 15:08:49 -0400668 if (!mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669 {
670 delete newRenderTargetStorage;
671 return gl::error(GL_OUT_OF_MEMORY, false);
672 }
673
674 setCompleteTexStorage(newRenderTargetStorage);
675 }
676 }
677
678 return (mTexStorage && mTexStorage->isRenderTarget());
679}
680
681TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
682{
683 return mTexStorage;
684}
685
686const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
687{
688 return mImageArray[0];
689}
690
691void TextureD3D_2D::updateStorageLevel(int level)
692{
693 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
694 ASSERT(isLevelComplete(level));
695
696 if (mImageArray[level]->isDirty())
697 {
698 commitRect(level, 0, 0, getWidth(level), getHeight(level));
699 }
700}
701
702void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
703{
704 // If there currently is a corresponding storage texture image, it has these parameters
705 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
706 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
707 const GLenum storageFormat = getBaseLevelInternalFormat();
708
709 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
710
711 if (mTexStorage)
712 {
713 const int storageLevels = mTexStorage->getLevelCount();
714
715 if ((level >= storageLevels && storageLevels != 0) ||
716 width != storageWidth ||
717 height != storageHeight ||
718 internalformat != storageFormat) // Discard mismatched storage
719 {
720 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
721 {
722 mImageArray[i]->markDirty();
723 }
724
725 SafeDelete(mTexStorage);
726 mDirtyImages = true;
727 }
728 }
729}
730
731void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
732{
733 if (isValidLevel(level))
734 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700735 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -0400736 if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700737 {
738 image->markClean();
739 }
740 }
741}
742
Brandon Jones0511e802014-07-14 16:27:26 -0700743
Brandon Jones78b1acd2014-07-15 15:33:07 -0700744TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700745 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700746 mTexStorage(NULL)
747{
748 for (int i = 0; i < 6; i++)
749 {
750 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
751 {
752 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
753 }
754 }
755}
756
757TextureD3D_Cube::~TextureD3D_Cube()
758{
Austin Kinross69822602014-08-12 15:51:37 -0700759 // Delete the Images before the TextureStorage.
760 // Images might be relying on the TextureStorage for some of their data.
761 // 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 -0700762 for (int i = 0; i < 6; i++)
763 {
764 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
765 {
766 SafeDelete(mImageArray[i][j]);
767 }
768 }
Austin Kinross69822602014-08-12 15:51:37 -0700769
770 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700771}
772
Brandon Jonescef06ff2014-08-05 13:27:48 -0700773Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700774{
775 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700776 ASSERT(layer < 6);
777 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700778}
779
Jamie Madillfeda4d22014-09-17 13:03:29 -0400780Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
781{
782 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
783 ASSERT(index.layerIndex < 6);
784 return mImageArray[index.layerIndex][index.mipIndex];
785}
786
Brandon Jonescef06ff2014-08-05 13:27:48 -0700787GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700788{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
790 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700791}
792
Brandon Jonescef06ff2014-08-05 13:27:48 -0700793GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700794{
795 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700796 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700797 else
798 return GL_NONE;
799}
800
Brandon Jonescef06ff2014-08-05 13:27:48 -0700801bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700802{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700803 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700804}
805
Brandon Jonescef06ff2014-08-05 13:27:48 -0700806void 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 -0700807{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700808 ASSERT(depth == 1);
809
810 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400811 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700812
813 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
814
815 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
816}
817
Brandon Jonescef06ff2014-08-05 13:27:48 -0700818void 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 -0700819{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700820 ASSERT(depth == 1);
821
Brandon Jones0511e802014-07-14 16:27:26 -0700822 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700823 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
824
Brandon Jones0511e802014-07-14 16:27:26 -0700825 redefineImage(faceIndex, level, format, width, height);
826
827 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
828}
829
Brandon Jonescef06ff2014-08-05 13:27:48 -0700830void 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 -0700831{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700832 ASSERT(depth == 1 && zoffset == 0);
833
834 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
835
Jamie Madillfeda4d22014-09-17 13:03:29 -0400836 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
837 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700838 {
839 commitRect(faceIndex, level, xoffset, yoffset, width, height);
840 }
841}
842
Brandon Jonescef06ff2014-08-05 13:27:48 -0700843void 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 -0700844{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700845 ASSERT(depth == 1 && zoffset == 0);
846
847 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
848
Brandon Jones0511e802014-07-14 16:27:26 -0700849 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
850 {
851 commitRect(faceIndex, level, xoffset, yoffset, width, height);
852 }
853}
854
855void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
856{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700857 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400858 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
859
Brandon Jones0511e802014-07-14 16:27:26 -0700860 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
861
862 if (!mImageArray[faceIndex][level]->isRenderableFormat())
863 {
864 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
865 mDirtyImages = true;
866 }
867 else
868 {
869 ensureRenderTarget();
870 mImageArray[faceIndex][level]->markClean();
871
872 ASSERT(width == height);
873
874 if (width > 0 && isValidFaceLevel(faceIndex, level))
875 {
876 gl::Rectangle sourceRect;
877 sourceRect.x = x;
878 sourceRect.width = width;
879 sourceRect.y = y;
880 sourceRect.height = height;
881
Jamie Madill856d9d42014-09-18 15:08:49 -0400882 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700883 }
884 }
885}
886
887void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
888{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700889 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700890
891 // We can only make our texture storage to a render target if the level we're copying *to* is complete
892 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
893 // rely on the "getBaseLevel*" methods reliably otherwise.
894 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
895
896 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
897 {
898 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
899 mDirtyImages = true;
900 }
901 else
902 {
903 ensureRenderTarget();
904
905 if (isValidFaceLevel(faceIndex, level))
906 {
907 updateStorageFaceLevel(faceIndex, level);
908
909 gl::Rectangle sourceRect;
910 sourceRect.x = x;
911 sourceRect.width = width;
912 sourceRect.y = y;
913 sourceRect.height = height;
914
Jamie Madill856d9d42014-09-18 15:08:49 -0400915 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
916 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700917 }
918 }
919}
920
Brandon Jonescef06ff2014-08-05 13:27:48 -0700921void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700922{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700923 ASSERT(width == height);
924 ASSERT(depth == 1);
925
Brandon Jones0511e802014-07-14 16:27:26 -0700926 for (int level = 0; level < levels; level++)
927 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700928 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700929 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
930 {
931 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
932 }
933 }
934
935 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
936 {
937 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
938 {
939 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
940 }
941 }
942
943 mImmutable = true;
944
Jamie Madillc4833262014-09-18 16:18:26 -0400945 bool renderTarget = IsRenderTargetUsage(mUsage);
946 TextureStorage *storageInstance = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -0400947 setCompleteTexStorage(new TextureStorageInterface(storageInstance, 6));
Brandon Jones0511e802014-07-14 16:27:26 -0700948}
949
Brandon Jones0511e802014-07-14 16:27:26 -0700950// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
951bool TextureD3D_Cube::isCubeComplete() const
952{
953 int baseWidth = getBaseLevelWidth();
954 int baseHeight = getBaseLevelHeight();
955 GLenum baseFormat = getBaseLevelInternalFormat();
956
957 if (baseWidth <= 0 || baseWidth != baseHeight)
958 {
959 return false;
960 }
961
962 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
963 {
964 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
965
966 if (faceBaseImage.getWidth() != baseWidth ||
967 faceBaseImage.getHeight() != baseHeight ||
968 faceBaseImage.getInternalFormat() != baseFormat )
969 {
970 return false;
971 }
972 }
973
974 return true;
975}
976
Brandon Jones6053a522014-07-25 16:22:09 -0700977void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
978{
979 UNREACHABLE();
980}
981
982void TextureD3D_Cube::releaseTexImage()
983{
984 UNREACHABLE();
985}
986
987
Brandon Jones0511e802014-07-14 16:27:26 -0700988void TextureD3D_Cube::generateMipmaps()
989{
990 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
991 int levelCount = mipLevels();
992 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
993 {
994 for (int level = 1; level < levelCount; level++)
995 {
996 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
997 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
998 }
999 }
1000
1001 if (mTexStorage && mTexStorage->isRenderTarget())
1002 {
Jamie Madill5e48c032014-09-18 15:08:47 -04001003 mTexStorage->getStorageInstance()->generateMipmaps();
1004
Brandon Jones0511e802014-07-14 16:27:26 -07001005 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1006 {
1007 for (int level = 1; level < levelCount; level++)
1008 {
Brandon Jones0511e802014-07-14 16:27:26 -07001009 mImageArray[faceIndex][level]->markClean();
1010 }
1011 }
1012 }
1013 else
1014 {
1015 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1016 {
1017 for (int level = 1; level < levelCount; level++)
1018 {
1019 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1020 }
1021 }
1022 }
1023}
1024
Jamie Madillac7579c2014-09-17 16:59:33 -04001025unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001026{
Jamie Madillc4833262014-09-18 16:18:26 -04001027 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001028}
1029
Jamie Madillac7579c2014-09-17 16:59:33 -04001030RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001031{
Jamie Madillac7579c2014-09-17 16:59:33 -04001032 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001033
1034 // ensure the underlying texture is created
1035 if (!ensureRenderTarget())
1036 {
1037 return NULL;
1038 }
1039
Jamie Madillac7579c2014-09-17 16:59:33 -04001040 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1041 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001042}
1043
Brandon Jones0511e802014-07-14 16:27:26 -07001044void TextureD3D_Cube::initializeStorage(bool renderTarget)
1045{
1046 // Only initialize the first time this texture is used as a render target or shader resource
1047 if (mTexStorage)
1048 {
1049 return;
1050 }
1051
1052 // do not attempt to create storage for nonexistant data
1053 if (!isFaceLevelComplete(0, 0))
1054 {
1055 return;
1056 }
1057
1058 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1059
1060 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1061 ASSERT(mTexStorage);
1062
1063 // flush image data to the storage
1064 updateStorage();
1065}
1066
Jamie Madill856d9d42014-09-18 15:08:49 -04001067TextureStorageInterface *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001068{
1069 GLsizei size = getBaseLevelWidth();
1070
1071 ASSERT(size > 0);
1072
1073 // use existing storage level count, when previously specified by TexStorage*D
1074 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1075
Jamie Madillc4833262014-09-18 16:18:26 -04001076 TextureStorage *storage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -04001077 return new TextureStorageInterface(storage, 6);
Brandon Jones0511e802014-07-14 16:27:26 -07001078}
1079
Jamie Madill856d9d42014-09-18 15:08:49 -04001080void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterface *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001081{
1082 SafeDelete(mTexStorage);
1083 mTexStorage = newCompleteTexStorage;
1084
1085 if (mTexStorage && mTexStorage->isManaged())
1086 {
1087 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1088 {
1089 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1090 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001091 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001092 }
1093 }
1094 }
1095
1096 mDirtyImages = true;
1097}
1098
1099void TextureD3D_Cube::updateStorage()
1100{
1101 ASSERT(mTexStorage != NULL);
1102 GLint storageLevels = mTexStorage->getLevelCount();
1103 for (int face = 0; face < 6; face++)
1104 {
1105 for (int level = 0; level < storageLevels; level++)
1106 {
1107 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1108 {
1109 updateStorageFaceLevel(face, level);
1110 }
1111 }
1112 }
1113}
1114
1115bool TextureD3D_Cube::ensureRenderTarget()
1116{
1117 initializeStorage(true);
1118
1119 if (getBaseLevelWidth() > 0)
1120 {
1121 ASSERT(mTexStorage);
1122 if (!mTexStorage->isRenderTarget())
1123 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001124 TextureStorageInterface *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001125
Jamie Madill856d9d42014-09-18 15:08:49 -04001126 if (!mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage))
Brandon Jones0511e802014-07-14 16:27:26 -07001127 {
1128 delete newRenderTargetStorage;
1129 return gl::error(GL_OUT_OF_MEMORY, false);
1130 }
1131
1132 setCompleteTexStorage(newRenderTargetStorage);
1133 }
1134 }
1135
1136 return (mTexStorage && mTexStorage->isRenderTarget());
1137}
1138
1139TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1140{
1141 return mTexStorage;
1142}
1143
1144const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1145{
1146 // Note: if we are not cube-complete, there is no single base level image that can describe all
1147 // cube faces, so this method is only well-defined for a cube-complete base level.
1148 return mImageArray[0][0];
1149}
1150
Brandon Jones0511e802014-07-14 16:27:26 -07001151bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1152{
1153 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1154}
1155
Brandon Jones0511e802014-07-14 16:27:26 -07001156bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1157{
1158 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1159
1160 if (isImmutable())
1161 {
1162 return true;
1163 }
1164
1165 int baseSize = getBaseLevelWidth();
1166
1167 if (baseSize <= 0)
1168 {
1169 return false;
1170 }
1171
1172 // "isCubeComplete" checks for base level completeness and we must call that
1173 // to determine if any face at level 0 is complete. We omit that check here
1174 // to avoid re-checking cube-completeness for every face at level 0.
1175 if (level == 0)
1176 {
1177 return true;
1178 }
1179
1180 // Check that non-zero levels are consistent with the base level.
1181 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1182
1183 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1184 {
1185 return false;
1186 }
1187
1188 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1189 {
1190 return false;
1191 }
1192
1193 return true;
1194}
1195
1196void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1197{
1198 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1199 ImageD3D *image = mImageArray[faceIndex][level];
1200
1201 if (image->isDirty())
1202 {
1203 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1204 }
1205}
1206
1207void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1208{
1209 // If there currently is a corresponding storage texture image, it has these parameters
1210 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1211 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1212 const GLenum storageFormat = getBaseLevelInternalFormat();
1213
1214 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1215
1216 if (mTexStorage)
1217 {
1218 const int storageLevels = mTexStorage->getLevelCount();
1219
1220 if ((level >= storageLevels && storageLevels != 0) ||
1221 width != storageWidth ||
1222 height != storageHeight ||
1223 internalformat != storageFormat) // Discard mismatched storage
1224 {
1225 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1226 {
1227 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1228 {
1229 mImageArray[faceIndex][level]->markDirty();
1230 }
1231 }
1232
1233 SafeDelete(mTexStorage);
1234
1235 mDirtyImages = true;
1236 }
1237 }
1238}
1239
1240void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1241{
1242 if (isValidFaceLevel(faceIndex, level))
1243 {
1244 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001245 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001246 image->markClean();
1247 }
1248}
1249
Brandon Jones78b1acd2014-07-15 15:33:07 -07001250
1251TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001252 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001253 mTexStorage(NULL)
1254{
1255 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1256 {
1257 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1258 }
1259}
1260
1261TextureD3D_3D::~TextureD3D_3D()
1262{
Austin Kinross69822602014-08-12 15:51:37 -07001263 // Delete the Images before the TextureStorage.
1264 // Images might be relying on the TextureStorage for some of their data.
1265 // 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 -07001266 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1267 {
1268 delete mImageArray[i];
1269 }
Austin Kinross69822602014-08-12 15:51:37 -07001270
1271 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001272}
1273
Brandon Jonescef06ff2014-08-05 13:27:48 -07001274Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001275{
1276 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001277 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001278 return mImageArray[level];
1279}
1280
Jamie Madillfeda4d22014-09-17 13:03:29 -04001281Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1282{
1283 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001284 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001285 ASSERT(index.type == GL_TEXTURE_3D);
1286 return mImageArray[index.mipIndex];
1287}
1288
Brandon Jonescef06ff2014-08-05 13:27:48 -07001289GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001290{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001291 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1292 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001293}
1294
Brandon Jones78b1acd2014-07-15 15:33:07 -07001295GLsizei TextureD3D_3D::getWidth(GLint level) const
1296{
1297 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1298 return mImageArray[level]->getWidth();
1299 else
1300 return 0;
1301}
1302
1303GLsizei TextureD3D_3D::getHeight(GLint level) const
1304{
1305 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1306 return mImageArray[level]->getHeight();
1307 else
1308 return 0;
1309}
1310
1311GLsizei TextureD3D_3D::getDepth(GLint level) const
1312{
1313 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1314 return mImageArray[level]->getDepth();
1315 else
1316 return 0;
1317}
1318
1319GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1320{
1321 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1322 return mImageArray[level]->getInternalFormat();
1323 else
1324 return GL_NONE;
1325}
1326
1327bool TextureD3D_3D::isDepth(GLint level) const
1328{
Geoff Lang5d601382014-07-22 15:14:06 -04001329 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001330}
1331
Brandon Jonescef06ff2014-08-05 13:27:48 -07001332void 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 -07001333{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001334 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001335 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1336
Brandon Jones78b1acd2014-07-15 15:33:07 -07001337 redefineImage(level, sizedInternalFormat, width, height, depth);
1338
1339 bool fastUnpacked = false;
1340
1341 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1342 if (isFastUnpackable(unpack, sizedInternalFormat))
1343 {
1344 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001345 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1346 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001347 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1348
1349 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1350 {
1351 // Ensure we don't overwrite our newly initialized data
1352 mImageArray[level]->markClean();
1353
1354 fastUnpacked = true;
1355 }
1356 }
1357
1358 if (!fastUnpacked)
1359 {
1360 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1361 }
1362}
1363
Brandon Jonescef06ff2014-08-05 13:27:48 -07001364void 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 -07001365{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001366 ASSERT(target == GL_TEXTURE_3D);
1367
Brandon Jones78b1acd2014-07-15 15:33:07 -07001368 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1369 redefineImage(level, format, width, height, depth);
1370
1371 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1372}
1373
Brandon Jonescef06ff2014-08-05 13:27:48 -07001374void 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 -07001375{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001376 ASSERT(target == GL_TEXTURE_3D);
1377
Brandon Jones78b1acd2014-07-15 15:33:07 -07001378 bool fastUnpacked = false;
1379
Jamie Madillac7579c2014-09-17 16:59:33 -04001380 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1381
Brandon Jones78b1acd2014-07-15 15:33:07 -07001382 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1383 if (isFastUnpackable(unpack, getInternalFormat(level)))
1384 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001385 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1387
1388 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1389 {
1390 // Ensure we don't overwrite our newly initialized data
1391 mImageArray[level]->markClean();
1392
1393 fastUnpacked = true;
1394 }
1395 }
1396
Jamie Madillfeda4d22014-09-17 13:03:29 -04001397 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398 {
1399 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1400 }
1401}
1402
Brandon Jonescef06ff2014-08-05 13:27:48 -07001403void 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 -07001404{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001405 ASSERT(target == GL_TEXTURE_3D);
1406
Brandon Jones78b1acd2014-07-15 15:33:07 -07001407 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1408 {
1409 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1410 }
1411}
1412
Brandon Jonescef06ff2014-08-05 13:27:48 -07001413void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1414{
1415 UNIMPLEMENTED();
1416}
1417
Brandon Jones78b1acd2014-07-15 15:33:07 -07001418void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1419{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001420 ASSERT(target == GL_TEXTURE_3D);
1421
Brandon Jones78b1acd2014-07-15 15:33:07 -07001422 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1423 // the current level we're copying to is defined (with appropriate format, width & height)
1424 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1425
1426 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1427 {
1428 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1429 mDirtyImages = true;
1430 }
1431 else
1432 {
1433 ensureRenderTarget();
1434
1435 if (isValidLevel(level))
1436 {
1437 updateStorageLevel(level);
1438
1439 gl::Rectangle sourceRect;
1440 sourceRect.x = x;
1441 sourceRect.width = width;
1442 sourceRect.y = y;
1443 sourceRect.height = height;
1444
Jamie Madill856d9d42014-09-18 15:08:49 -04001445 mRenderer->copyImage3D(source, sourceRect,
1446 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1447 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001448 }
1449 }
1450}
1451
Brandon Jonescef06ff2014-08-05 13:27:48 -07001452void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001453{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001454 ASSERT(target == GL_TEXTURE_3D);
1455
Brandon Jones78b1acd2014-07-15 15:33:07 -07001456 for (int level = 0; level < levels; level++)
1457 {
1458 GLsizei levelWidth = std::max(1, width >> level);
1459 GLsizei levelHeight = std::max(1, height >> level);
1460 GLsizei levelDepth = std::max(1, depth >> level);
1461 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1462 }
1463
1464 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1465 {
1466 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1467 }
1468
1469 mImmutable = true;
1470
Jamie Madillc4833262014-09-18 16:18:26 -04001471 bool renderTarget = IsRenderTargetUsage(mUsage);
1472 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -04001473 setCompleteTexStorage(new TextureStorageInterface(storage, depth));
Brandon Jones78b1acd2014-07-15 15:33:07 -07001474}
1475
Brandon Jones6053a522014-07-25 16:22:09 -07001476void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001477{
Brandon Jones6053a522014-07-25 16:22:09 -07001478 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479}
1480
Brandon Jones6053a522014-07-25 16:22:09 -07001481void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001482{
Brandon Jones6053a522014-07-25 16:22:09 -07001483 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001484}
1485
Brandon Jones6053a522014-07-25 16:22:09 -07001486
Brandon Jones78b1acd2014-07-15 15:33:07 -07001487void TextureD3D_3D::generateMipmaps()
1488{
1489 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1490 int levelCount = mipLevels();
1491 for (int level = 1; level < levelCount; level++)
1492 {
1493 redefineImage(level, getBaseLevelInternalFormat(),
1494 std::max(getBaseLevelWidth() >> level, 1),
1495 std::max(getBaseLevelHeight() >> level, 1),
1496 std::max(getBaseLevelDepth() >> level, 1));
1497 }
1498
1499 if (mTexStorage && mTexStorage->isRenderTarget())
1500 {
Jamie Madill5e48c032014-09-18 15:08:47 -04001501 mTexStorage->getStorageInstance()->generateMipmaps();
1502
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503 for (int level = 1; level < levelCount; level++)
1504 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001505 mImageArray[level]->markClean();
1506 }
1507 }
1508 else
1509 {
1510 for (int level = 1; level < levelCount; level++)
1511 {
1512 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1513 }
1514 }
1515}
1516
Jamie Madillac7579c2014-09-17 16:59:33 -04001517unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001518{
Jamie Madillc4833262014-09-18 16:18:26 -04001519 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001520}
1521
Jamie Madillac7579c2014-09-17 16:59:33 -04001522RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523{
1524 // ensure the underlying texture is created
1525 if (!ensureRenderTarget())
1526 {
1527 return NULL;
1528 }
1529
Jamie Madillac7579c2014-09-17 16:59:33 -04001530 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001532 updateStorage();
1533 }
1534 else
1535 {
1536 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001537 }
1538
Jamie Madillac7579c2014-09-17 16:59:33 -04001539 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540}
1541
1542void TextureD3D_3D::initializeStorage(bool renderTarget)
1543{
1544 // Only initialize the first time this texture is used as a render target or shader resource
1545 if (mTexStorage)
1546 {
1547 return;
1548 }
1549
1550 // do not attempt to create storage for nonexistant data
1551 if (!isLevelComplete(0))
1552 {
1553 return;
1554 }
1555
1556 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1557
1558 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1559 ASSERT(mTexStorage);
1560
1561 // flush image data to the storage
1562 updateStorage();
1563}
1564
Jamie Madill856d9d42014-09-18 15:08:49 -04001565TextureStorageInterface *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001566{
1567 GLsizei width = getBaseLevelWidth();
1568 GLsizei height = getBaseLevelHeight();
1569 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001570 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001571
1572 ASSERT(width > 0 && height > 0 && depth > 0);
1573
1574 // use existing storage level count, when previously specified by TexStorage*D
1575 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1576
Jamie Madillc4833262014-09-18 16:18:26 -04001577 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -04001578 return new TextureStorageInterface(storage, depth);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001579}
1580
Jamie Madill856d9d42014-09-18 15:08:49 -04001581void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001582{
1583 SafeDelete(mTexStorage);
1584 mTexStorage = newCompleteTexStorage;
1585 mDirtyImages = true;
1586
1587 // We do not support managed 3D storage, as that is D3D9/ES2-only
1588 ASSERT(!mTexStorage->isManaged());
1589}
1590
1591void TextureD3D_3D::updateStorage()
1592{
1593 ASSERT(mTexStorage != NULL);
1594 GLint storageLevels = mTexStorage->getLevelCount();
1595 for (int level = 0; level < storageLevels; level++)
1596 {
1597 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1598 {
1599 updateStorageLevel(level);
1600 }
1601 }
1602}
1603
1604bool TextureD3D_3D::ensureRenderTarget()
1605{
1606 initializeStorage(true);
1607
1608 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1609 {
1610 ASSERT(mTexStorage);
1611 if (!mTexStorage->isRenderTarget())
1612 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001613 TextureStorageInterface *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001614
Jamie Madill856d9d42014-09-18 15:08:49 -04001615 if (!mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616 {
1617 delete newRenderTargetStorage;
1618 return gl::error(GL_OUT_OF_MEMORY, false);
1619 }
1620
1621 setCompleteTexStorage(newRenderTargetStorage);
1622 }
1623 }
1624
1625 return (mTexStorage && mTexStorage->isRenderTarget());
1626}
1627
1628TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1629{
1630 return mTexStorage;
1631}
1632
1633const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1634{
1635 return mImageArray[0];
1636}
1637
1638bool TextureD3D_3D::isValidLevel(int level) const
1639{
1640 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1641}
1642
1643bool TextureD3D_3D::isLevelComplete(int level) const
1644{
1645 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1646
1647 if (isImmutable())
1648 {
1649 return true;
1650 }
1651
1652 GLsizei width = getBaseLevelWidth();
1653 GLsizei height = getBaseLevelHeight();
1654 GLsizei depth = getBaseLevelDepth();
1655
1656 if (width <= 0 || height <= 0 || depth <= 0)
1657 {
1658 return false;
1659 }
1660
1661 if (level == 0)
1662 {
1663 return true;
1664 }
1665
1666 ImageD3D *levelImage = mImageArray[level];
1667
1668 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1669 {
1670 return false;
1671 }
1672
1673 if (levelImage->getWidth() != std::max(1, width >> level))
1674 {
1675 return false;
1676 }
1677
1678 if (levelImage->getHeight() != std::max(1, height >> level))
1679 {
1680 return false;
1681 }
1682
1683 if (levelImage->getDepth() != std::max(1, depth >> level))
1684 {
1685 return false;
1686 }
1687
1688 return true;
1689}
1690
1691void TextureD3D_3D::updateStorageLevel(int level)
1692{
1693 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1694 ASSERT(isLevelComplete(level));
1695
1696 if (mImageArray[level]->isDirty())
1697 {
1698 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1699 }
1700}
1701
1702void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1703{
1704 // If there currently is a corresponding storage texture image, it has these parameters
1705 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1706 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1707 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1708 const GLenum storageFormat = getBaseLevelInternalFormat();
1709
1710 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1711
1712 if (mTexStorage)
1713 {
1714 const int storageLevels = mTexStorage->getLevelCount();
1715
1716 if ((level >= storageLevels && storageLevels != 0) ||
1717 width != storageWidth ||
1718 height != storageHeight ||
1719 depth != storageDepth ||
1720 internalformat != storageFormat) // Discard mismatched storage
1721 {
1722 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1723 {
1724 mImageArray[i]->markDirty();
1725 }
1726
1727 SafeDelete(mTexStorage);
1728 mDirtyImages = true;
1729 }
1730 }
1731}
1732
1733void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1734{
1735 if (isValidLevel(level))
1736 {
1737 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001738 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739 {
1740 image->markClean();
1741 }
1742 }
1743}
1744
Brandon Jones142ec422014-07-16 10:31:30 -07001745
1746TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001747 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001748 mTexStorage(NULL)
1749{
1750 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1751 {
1752 mLayerCounts[level] = 0;
1753 mImageArray[level] = NULL;
1754 }
1755}
1756
1757TextureD3D_2DArray::~TextureD3D_2DArray()
1758{
Austin Kinross69822602014-08-12 15:51:37 -07001759 // Delete the Images before the TextureStorage.
1760 // Images might be relying on the TextureStorage for some of their data.
1761 // 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 -07001762 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001763 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001764}
1765
Brandon Jones142ec422014-07-16 10:31:30 -07001766Image *TextureD3D_2DArray::getImage(int level, int layer) const
1767{
1768 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1769 ASSERT(layer < mLayerCounts[level]);
1770 return mImageArray[level][layer];
1771}
1772
Jamie Madillfeda4d22014-09-17 13:03:29 -04001773Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1774{
1775 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1776 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1777 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1778 return mImageArray[index.mipIndex][index.layerIndex];
1779}
1780
Brandon Jones142ec422014-07-16 10:31:30 -07001781GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1782{
1783 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1784 return mLayerCounts[level];
1785}
1786
Brandon Jones142ec422014-07-16 10:31:30 -07001787GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1788{
1789 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1790}
1791
1792GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1793{
1794 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1795}
1796
1797GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1798{
1799 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1800}
1801
1802GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1803{
1804 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1805}
1806
1807bool TextureD3D_2DArray::isDepth(GLint level) const
1808{
Geoff Lang5d601382014-07-22 15:14:06 -04001809 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001810}
1811
Brandon Jonescef06ff2014-08-05 13:27:48 -07001812void 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 -07001813{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001814 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1815
Geoff Lang5d601382014-07-22 15:14:06 -04001816 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1817
Brandon Jones142ec422014-07-16 10:31:30 -07001818 redefineImage(level, sizedInternalFormat, width, height, depth);
1819
Geoff Lang5d601382014-07-22 15:14:06 -04001820 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1821 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001822
1823 for (int i = 0; i < depth; i++)
1824 {
1825 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1826 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1827 }
1828}
1829
Brandon Jonescef06ff2014-08-05 13:27:48 -07001830void 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 -07001831{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001832 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1833
Brandon Jones142ec422014-07-16 10:31:30 -07001834 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1835 redefineImage(level, format, width, height, depth);
1836
Geoff Lang5d601382014-07-22 15:14:06 -04001837 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1838 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001839
1840 for (int i = 0; i < depth; i++)
1841 {
1842 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1843 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1844 }
1845}
1846
Brandon Jonescef06ff2014-08-05 13:27:48 -07001847void 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 -07001848{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001849 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1850
Geoff Lang5d601382014-07-22 15:14:06 -04001851 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1852 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001853
1854 for (int i = 0; i < depth; i++)
1855 {
1856 int layer = zoffset + i;
1857 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1858
Jamie Madillfeda4d22014-09-17 13:03:29 -04001859 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1860 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001861 {
1862 commitRect(level, xoffset, yoffset, layer, width, height);
1863 }
1864 }
1865}
1866
Brandon Jonescef06ff2014-08-05 13:27:48 -07001867void 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 -07001868{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001869 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1870
Geoff Lang5d601382014-07-22 15:14:06 -04001871 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1872 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001873
1874 for (int i = 0; i < depth; i++)
1875 {
1876 int layer = zoffset + i;
1877 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1878
1879 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1880 {
1881 commitRect(level, xoffset, yoffset, layer, width, height);
1882 }
1883 }
1884}
1885
Brandon Jonescef06ff2014-08-05 13:27:48 -07001886void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1887{
1888 UNIMPLEMENTED();
1889}
1890
Brandon Jones142ec422014-07-16 10:31:30 -07001891void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1892{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001893 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1894
Brandon Jones142ec422014-07-16 10:31:30 -07001895 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1896 // the current level we're copying to is defined (with appropriate format, width & height)
1897 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1898
1899 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1900 {
1901 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1902 mDirtyImages = true;
1903 }
1904 else
1905 {
1906 ensureRenderTarget();
1907
1908 if (isValidLevel(level))
1909 {
1910 updateStorageLevel(level);
1911
1912 gl::Rectangle sourceRect;
1913 sourceRect.x = x;
1914 sourceRect.width = width;
1915 sourceRect.y = y;
1916 sourceRect.height = height;
1917
Jamie Madill856d9d42014-09-18 15:08:49 -04001918 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1919 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001920 }
1921 }
1922}
1923
Brandon Jonescef06ff2014-08-05 13:27:48 -07001924void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001925{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001926 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1927
Brandon Jones142ec422014-07-16 10:31:30 -07001928 deleteImages();
1929
1930 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1931 {
1932 GLsizei levelWidth = std::max(1, width >> level);
1933 GLsizei levelHeight = std::max(1, height >> level);
1934
1935 mLayerCounts[level] = (level < levels ? depth : 0);
1936
1937 if (mLayerCounts[level] > 0)
1938 {
1939 // Create new images for this level
1940 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1941
1942 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1943 {
1944 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1945 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1946 levelHeight, 1, true);
1947 }
1948 }
1949 }
1950
1951 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001952
1953 bool renderTarget = IsRenderTargetUsage(mUsage);
1954 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -04001955 setCompleteTexStorage(new TextureStorageInterface(storage, depth));
Brandon Jones142ec422014-07-16 10:31:30 -07001956}
1957
Brandon Jones6053a522014-07-25 16:22:09 -07001958void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001959{
Brandon Jones6053a522014-07-25 16:22:09 -07001960 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001961}
1962
Brandon Jones6053a522014-07-25 16:22:09 -07001963void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001964{
Brandon Jones6053a522014-07-25 16:22:09 -07001965 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001966}
1967
Brandon Jones6053a522014-07-25 16:22:09 -07001968
Brandon Jones142ec422014-07-16 10:31:30 -07001969void TextureD3D_2DArray::generateMipmaps()
1970{
1971 int baseWidth = getBaseLevelWidth();
1972 int baseHeight = getBaseLevelHeight();
1973 int baseDepth = getBaseLevelDepth();
1974 GLenum baseFormat = getBaseLevelInternalFormat();
1975
1976 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1977 int levelCount = mipLevels();
1978 for (int level = 1; level < levelCount; level++)
1979 {
1980 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1981 }
1982
1983 if (mTexStorage && mTexStorage->isRenderTarget())
1984 {
Jamie Madill5e48c032014-09-18 15:08:47 -04001985 mTexStorage->getStorageInstance()->generateMipmaps();
1986
Brandon Jones142ec422014-07-16 10:31:30 -07001987 for (int level = 1; level < levelCount; level++)
1988 {
Brandon Jones142ec422014-07-16 10:31:30 -07001989 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1990 {
1991 mImageArray[level][layer]->markClean();
1992 }
1993 }
1994 }
1995 else
1996 {
1997 for (int level = 1; level < levelCount; level++)
1998 {
1999 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2000 {
2001 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2002 }
2003 }
2004 }
2005}
2006
Jamie Madillac7579c2014-09-17 16:59:33 -04002007unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002008{
Jamie Madillc4833262014-09-18 16:18:26 -04002009 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002010}
2011
Jamie Madillac7579c2014-09-17 16:59:33 -04002012RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002013{
2014 // ensure the underlying texture is created
2015 if (!ensureRenderTarget())
2016 {
2017 return NULL;
2018 }
2019
Jamie Madillac7579c2014-09-17 16:59:33 -04002020 updateStorageLevel(index.mipIndex);
2021 return mTexStorage->getStorageInstance()->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002022}
2023
2024void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2025{
2026 // Only initialize the first time this texture is used as a render target or shader resource
2027 if (mTexStorage)
2028 {
2029 return;
2030 }
2031
2032 // do not attempt to create storage for nonexistant data
2033 if (!isLevelComplete(0))
2034 {
2035 return;
2036 }
2037
2038 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2039
2040 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2041 ASSERT(mTexStorage);
2042
2043 // flush image data to the storage
2044 updateStorage();
2045}
2046
Jamie Madill856d9d42014-09-18 15:08:49 -04002047TextureStorageInterface *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002048{
2049 GLsizei width = getBaseLevelWidth();
2050 GLsizei height = getBaseLevelHeight();
2051 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002052 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002053
2054 ASSERT(width > 0 && height > 0 && depth > 0);
2055
2056 // use existing storage level count, when previously specified by TexStorage*D
2057 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2058
Jamie Madillc4833262014-09-18 16:18:26 -04002059 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Jamie Madill856d9d42014-09-18 15:08:49 -04002060 return new TextureStorageInterface(storage, depth);
Brandon Jones142ec422014-07-16 10:31:30 -07002061}
2062
Jamie Madill856d9d42014-09-18 15:08:49 -04002063void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002064{
2065 SafeDelete(mTexStorage);
2066 mTexStorage = newCompleteTexStorage;
2067 mDirtyImages = true;
2068
2069 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2070 ASSERT(!mTexStorage->isManaged());
2071}
2072
2073void TextureD3D_2DArray::updateStorage()
2074{
2075 ASSERT(mTexStorage != NULL);
2076 GLint storageLevels = mTexStorage->getLevelCount();
2077 for (int level = 0; level < storageLevels; level++)
2078 {
2079 if (isLevelComplete(level))
2080 {
2081 updateStorageLevel(level);
2082 }
2083 }
2084}
2085
2086bool TextureD3D_2DArray::ensureRenderTarget()
2087{
2088 initializeStorage(true);
2089
2090 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2091 {
2092 ASSERT(mTexStorage);
2093 if (!mTexStorage->isRenderTarget())
2094 {
Jamie Madill856d9d42014-09-18 15:08:49 -04002095 TextureStorageInterface *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002096
Jamie Madill856d9d42014-09-18 15:08:49 -04002097 if (!mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage))
Brandon Jones142ec422014-07-16 10:31:30 -07002098 {
2099 delete newRenderTargetStorage;
2100 return gl::error(GL_OUT_OF_MEMORY, false);
2101 }
2102
2103 setCompleteTexStorage(newRenderTargetStorage);
2104 }
2105 }
2106
2107 return (mTexStorage && mTexStorage->isRenderTarget());
2108}
2109
2110const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2111{
2112 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2113}
2114
2115TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2116{
2117 return mTexStorage;
2118}
2119
2120bool TextureD3D_2DArray::isValidLevel(int level) const
2121{
2122 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2123}
2124
2125bool TextureD3D_2DArray::isLevelComplete(int level) const
2126{
2127 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2128
2129 if (isImmutable())
2130 {
2131 return true;
2132 }
2133
2134 GLsizei width = getBaseLevelWidth();
2135 GLsizei height = getBaseLevelHeight();
2136 GLsizei layers = getLayers(0);
2137
2138 if (width <= 0 || height <= 0 || layers <= 0)
2139 {
2140 return false;
2141 }
2142
2143 if (level == 0)
2144 {
2145 return true;
2146 }
2147
2148 if (getInternalFormat(level) != getInternalFormat(0))
2149 {
2150 return false;
2151 }
2152
2153 if (getWidth(level) != std::max(1, width >> level))
2154 {
2155 return false;
2156 }
2157
2158 if (getHeight(level) != std::max(1, height >> level))
2159 {
2160 return false;
2161 }
2162
2163 if (getLayers(level) != layers)
2164 {
2165 return false;
2166 }
2167
2168 return true;
2169}
2170
2171void TextureD3D_2DArray::updateStorageLevel(int level)
2172{
2173 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2174 ASSERT(isLevelComplete(level));
2175
2176 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2177 {
2178 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2179 if (mImageArray[level][layer]->isDirty())
2180 {
2181 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2182 }
2183 }
2184}
2185
2186void TextureD3D_2DArray::deleteImages()
2187{
2188 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2189 {
2190 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2191 {
2192 delete mImageArray[level][layer];
2193 }
2194 delete[] mImageArray[level];
2195 mImageArray[level] = NULL;
2196 mLayerCounts[level] = 0;
2197 }
2198}
2199
2200void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2201{
2202 // If there currently is a corresponding storage texture image, it has these parameters
2203 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2204 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2205 const int storageDepth = getLayers(0);
2206 const GLenum storageFormat = getBaseLevelInternalFormat();
2207
2208 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2209 {
2210 delete mImageArray[level][layer];
2211 }
2212 delete[] mImageArray[level];
2213 mImageArray[level] = NULL;
2214 mLayerCounts[level] = depth;
2215
2216 if (depth > 0)
2217 {
2218 mImageArray[level] = new ImageD3D*[depth]();
2219
2220 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2221 {
2222 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2223 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2224 }
2225 }
2226
2227 if (mTexStorage)
2228 {
2229 const int storageLevels = mTexStorage->getLevelCount();
2230
2231 if ((level >= storageLevels && storageLevels != 0) ||
2232 width != storageWidth ||
2233 height != storageHeight ||
2234 depth != storageDepth ||
2235 internalformat != storageFormat) // Discard mismatched storage
2236 {
2237 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2238 {
2239 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2240 {
2241 mImageArray[level][layer]->markDirty();
2242 }
2243 }
2244
2245 delete mTexStorage;
2246 mTexStorage = NULL;
2247 mDirtyImages = true;
2248 }
2249 }
2250}
2251
2252void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2253{
2254 if (isValidLevel(level) && layerTarget < getLayers(level))
2255 {
2256 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002257 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002258 {
2259 image->markClean();
2260 }
2261 }
2262}
2263
Brandon Jones78b1acd2014-07-15 15:33:07 -07002264}