blob: 18e9e98053a80ab0941e7689b5590271e88616b1 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Brandon Jonesf47bebc2014-07-09 14:28:42 -070029bool IsRenderTargetUsage(GLenum usage)
30{
31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
32}
33
Brandon Jones78b1acd2014-07-15 15:33:07 -070034TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070035 : mRenderer(renderer),
36 mUsage(GL_NONE),
37 mDirtyImages(true),
38 mImmutable(false)
39{
40}
41
42TextureD3D::~TextureD3D()
43{
44}
45
Brandon Jones6053a522014-07-25 16:22:09 -070046TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
47{
48 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
49 return static_cast<TextureD3D*>(texture);
50}
51
Jamie Madill2f06dbf2014-09-18 15:08:50 -040052TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070053{
54 // ensure the underlying texture is created
55 initializeStorage(false);
56
Jamie Madill2f06dbf2014-09-18 15:08:50 -040057 TextureStorage *storage = getBaseLevelStorage();
Brandon Jones6053a522014-07-25 16:22:09 -070058 if (storage)
59 {
60 updateStorage();
61 }
62
63 return storage;
64}
65
Brandon Jonesf47bebc2014-07-09 14:28:42 -070066GLint TextureD3D::getBaseLevelWidth() const
67{
Brandon Jones78b1acd2014-07-15 15:33:07 -070068 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 return (baseImage ? baseImage->getWidth() : 0);
70}
71
72GLint TextureD3D::getBaseLevelHeight() const
73{
Brandon Jones78b1acd2014-07-15 15:33:07 -070074 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075 return (baseImage ? baseImage->getHeight() : 0);
76}
77
78GLint TextureD3D::getBaseLevelDepth() const
79{
Brandon Jones78b1acd2014-07-15 15:33:07 -070080 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070081 return (baseImage ? baseImage->getDepth() : 0);
82}
83
84// Note: "base level image" is loosely defined to be any image from the base level,
85// where in the base of 2D array textures and cube maps there are several. Don't use
86// the base level image for anything except querying texture format and size.
87GLenum TextureD3D::getBaseLevelInternalFormat() const
88{
Brandon Jones78b1acd2014-07-15 15:33:07 -070089 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070090 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
91}
92
Brandon Jones78b1acd2014-07-15 15:33:07 -070093void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
95 // No-op
96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
97 {
98 return;
99 }
100
101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
103 const void *pixelData = pixels;
104
105 if (unpack.pixelBuffer.id() != 0)
106 {
107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
111 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
112 const void *bufferData = pixelBuffer->getImplementation()->getData();
113 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
114 }
115
116 if (pixelData != NULL)
117 {
118 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 mDirtyImages = true;
120 }
121}
122
123bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillfeda4d22014-09-17 13:03:29 -0400124 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700125{
126 const void *pixelData = pixels;
127
128 // CPU readback & copy where direct GPU copy is not supported
129 if (unpack.pixelBuffer.id() != 0)
130 {
131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
132 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
134 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
135 const void *bufferData = pixelBuffer->getImplementation()->getData();
136 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
137 }
138
139 if (pixelData != NULL)
140 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400141 Image *image = getImage(index);
142 ASSERT(image);
143
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
145 mDirtyImages = true;
146 }
147
148 return true;
149}
150
Brandon Jones78b1acd2014-07-15 15:33:07 -0700151void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152{
153 if (pixels != NULL)
154 {
155 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
156 mDirtyImages = true;
157 }
158}
159
160bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700161 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162{
163 if (pixels != NULL)
164 {
165 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
166 mDirtyImages = true;
167 }
168
169 return true;
170}
171
172bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
173{
174 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
175}
176
177bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700178 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700179{
180 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
181 {
182 return true;
183 }
184
185 // In order to perform the fast copy through the shader, we must have the right format, and be able
186 // to create a render target.
187 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
188
189 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
190
191 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
192}
193
194GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
195{
196 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
197 {
198 // Maximum number of levels
199 return gl::log2(std::max(std::max(width, height), depth)) + 1;
200 }
201 else
202 {
203 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
204 return 1;
205 }
206}
207
208int TextureD3D::mipLevels() const
209{
210 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
211}
212
Jamie Madill4aa79e12014-09-29 10:46:14 -0400213void TextureD3D::generateMipmaps()
214{
215 // Set up proper image sizes.
216 initMipmapsImages();
217
218 // We know that all layers have the same dimension, for the texture to be complete
219 GLint layerCount = static_cast<GLint>(getLayerCount(0));
220 GLint mipCount = mipLevels();
221
222 // The following will create and initialize the storage, or update it if it exists
223 TextureStorage *storage = getNativeTexture();
224
225 bool renderableStorage = (storage && storage->isRenderTarget());
226
227 for (GLint layer = 0; layer < layerCount; ++layer)
228 {
229 for (GLint mip = 1; mip < mipCount; ++mip)
230 {
231 ASSERT(getLayerCount(mip) == layerCount);
232
233 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
234 gl::ImageIndex destIndex = getImageIndex(mip, layer);
235
236 if (renderableStorage)
237 {
238 // GPU-side mipmapping
239 storage->generateMipmap(sourceIndex, destIndex);
240 }
241 else
242 {
243 // CPU-side mipmapping
244 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
245 }
246 }
247 }
248}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700249
Brandon Jones78b1acd2014-07-15 15:33:07 -0700250TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700251 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700252 mTexStorage(NULL)
253{
254 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
255 {
256 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
257 }
258}
259
260TextureD3D_2D::~TextureD3D_2D()
261{
Austin Kinross69822602014-08-12 15:51:37 -0700262 // Delete the Images before the TextureStorage.
263 // Images might be relying on the TextureStorage for some of their data.
264 // 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 -0700265 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
266 {
267 delete mImageArray[i];
268 }
Austin Kinross69822602014-08-12 15:51:37 -0700269
270 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700271}
272
Brandon Jonescef06ff2014-08-05 13:27:48 -0700273Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700274{
275 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700276 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700277 return mImageArray[level];
278}
279
Jamie Madillfeda4d22014-09-17 13:03:29 -0400280Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
281{
282 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400283 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400284 ASSERT(index.type == GL_TEXTURE_2D);
285 return mImageArray[index.mipIndex];
286}
287
Brandon Jonescef06ff2014-08-05 13:27:48 -0700288GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700289{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700290 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
291 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700292}
293
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294GLsizei TextureD3D_2D::getWidth(GLint level) const
295{
296 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
297 return mImageArray[level]->getWidth();
298 else
299 return 0;
300}
301
302GLsizei TextureD3D_2D::getHeight(GLint level) const
303{
304 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
305 return mImageArray[level]->getHeight();
306 else
307 return 0;
308}
309
310GLenum TextureD3D_2D::getInternalFormat(GLint level) const
311{
312 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
313 return mImageArray[level]->getInternalFormat();
314 else
315 return GL_NONE;
316}
317
318GLenum TextureD3D_2D::getActualFormat(GLint level) const
319{
320 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
321 return mImageArray[level]->getActualFormat();
322 else
323 return GL_NONE;
324}
325
326bool TextureD3D_2D::isDepth(GLint level) const
327{
Geoff Lang5d601382014-07-22 15:14:06 -0400328 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700329}
330
Brandon Jonescef06ff2014-08-05 13:27:48 -0700331void 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 -0700332{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700333 ASSERT(target == GL_TEXTURE_2D && depth == 1);
334
Geoff Lang5d601382014-07-22 15:14:06 -0400335 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
336
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700337 bool fastUnpacked = false;
338
Brandon Jonescef06ff2014-08-05 13:27:48 -0700339 redefineImage(level, sizedInternalFormat, width, height);
340
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700341 // Attempt a fast gpu copy of the pixel data to the surface
342 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
343 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400344 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
345
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700346 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400347 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700348 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
349
350 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
351 {
352 // Ensure we don't overwrite our newly initialized data
353 mImageArray[level]->markClean();
354
355 fastUnpacked = true;
356 }
357 }
358
359 if (!fastUnpacked)
360 {
361 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
362 }
363}
364
Brandon Jonescef06ff2014-08-05 13:27:48 -0700365void 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 -0700366{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700367 ASSERT(target == GL_TEXTURE_2D && depth == 1);
368
369 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
370 redefineImage(level, format, width, height);
371
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700372 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
373}
374
Brandon Jonescef06ff2014-08-05 13:27:48 -0700375void 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 -0700376{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700377 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
378
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700379 bool fastUnpacked = false;
380
Jamie Madillac7579c2014-09-17 16:59:33 -0400381 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700382 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
383 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400384 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700385 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
386
387 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
388 {
389 // Ensure we don't overwrite our newly initialized data
390 mImageArray[level]->markClean();
391
392 fastUnpacked = true;
393 }
394 }
395
Jamie Madillfeda4d22014-09-17 13:03:29 -0400396 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700397 {
398 commitRect(level, xoffset, yoffset, width, height);
399 }
400}
401
Brandon Jonescef06ff2014-08-05 13:27:48 -0700402void 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 -0700403{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700404 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
405
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700406 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
407 {
408 commitRect(level, xoffset, yoffset, width, height);
409 }
410}
411
Brandon Jonescef06ff2014-08-05 13:27:48 -0700412void 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 -0700413{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700414 ASSERT(target == GL_TEXTURE_2D);
415
416 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
417 redefineImage(level, sizedInternalFormat, width, height);
418
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700419 if (!mImageArray[level]->isRenderableFormat())
420 {
421 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
422 mDirtyImages = true;
423 }
424 else
425 {
426 ensureRenderTarget();
427 mImageArray[level]->markClean();
428
429 if (width != 0 && height != 0 && isValidLevel(level))
430 {
431 gl::Rectangle sourceRect;
432 sourceRect.x = x;
433 sourceRect.width = width;
434 sourceRect.y = y;
435 sourceRect.height = height;
436
Jamie Madill856d9d42014-09-18 15:08:49 -0400437 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700438 }
439 }
440}
441
442void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
443{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700444 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
445
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700446 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
447 // the current level we're copying to is defined (with appropriate format, width & height)
448 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
449
450 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
451 {
452 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
453 mDirtyImages = true;
454 }
455 else
456 {
457 ensureRenderTarget();
458
459 if (isValidLevel(level))
460 {
461 updateStorageLevel(level);
462
463 gl::Rectangle sourceRect;
464 sourceRect.x = x;
465 sourceRect.width = width;
466 sourceRect.y = y;
467 sourceRect.height = height;
468
Jamie Madill856d9d42014-09-18 15:08:49 -0400469 mRenderer->copyImage2D(source, sourceRect,
470 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
471 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700472 }
473 }
474}
475
Brandon Jonescef06ff2014-08-05 13:27:48 -0700476void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700477{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700478 ASSERT(target == GL_TEXTURE_2D && depth == 1);
479
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700480 for (int level = 0; level < levels; level++)
481 {
482 GLsizei levelWidth = std::max(1, width >> level);
483 GLsizei levelHeight = std::max(1, height >> level);
484 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
485 }
486
487 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
488 {
489 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
490 }
491
492 mImmutable = true;
493
Jamie Madillc4833262014-09-18 16:18:26 -0400494 bool renderTarget = IsRenderTargetUsage(mUsage);
495 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400496 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700497}
498
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700499void TextureD3D_2D::bindTexImage(egl::Surface *surface)
500{
501 GLenum internalformat = surface->getFormat();
502
503 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
504
505 if (mTexStorage)
506 {
507 SafeDelete(mTexStorage);
508 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400509
510 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700511
512 mDirtyImages = true;
513}
514
515void TextureD3D_2D::releaseTexImage()
516{
517 if (mTexStorage)
518 {
519 SafeDelete(mTexStorage);
520 }
521
522 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
523 {
524 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
525 }
526}
527
Jamie Madill4aa79e12014-09-29 10:46:14 -0400528void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700529{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700530 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532 for (int level = 1; level < levelCount; level++)
533 {
534 redefineImage(level, getBaseLevelInternalFormat(),
535 std::max(getBaseLevelWidth() >> level, 1),
536 std::max(getBaseLevelHeight() >> level, 1));
537 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538}
539
Jamie Madillac7579c2014-09-17 16:59:33 -0400540unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700541{
Jamie Madillac7579c2014-09-17 16:59:33 -0400542 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400543 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700544}
545
Jamie Madillac7579c2014-09-17 16:59:33 -0400546RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700547{
Jamie Madillac7579c2014-09-17 16:59:33 -0400548 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700549
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700550 // ensure the underlying texture is created
551 if (!ensureRenderTarget())
552 {
553 return NULL;
554 }
555
Jamie Madillac7579c2014-09-17 16:59:33 -0400556 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400557 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558}
559
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560bool TextureD3D_2D::isValidLevel(int level) const
561{
562 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
563}
564
565bool TextureD3D_2D::isLevelComplete(int level) const
566{
567 if (isImmutable())
568 {
569 return true;
570 }
571
Brandon Jones78b1acd2014-07-15 15:33:07 -0700572 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700573
574 GLsizei width = baseImage->getWidth();
575 GLsizei height = baseImage->getHeight();
576
577 if (width <= 0 || height <= 0)
578 {
579 return false;
580 }
581
582 // The base image level is complete if the width and height are positive
583 if (level == 0)
584 {
585 return true;
586 }
587
588 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700589 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700590
591 if (image->getInternalFormat() != baseImage->getInternalFormat())
592 {
593 return false;
594 }
595
596 if (image->getWidth() != std::max(1, width >> level))
597 {
598 return false;
599 }
600
601 if (image->getHeight() != std::max(1, height >> level))
602 {
603 return false;
604 }
605
606 return true;
607}
608
609// Constructs a native texture resource from the texture images
610void TextureD3D_2D::initializeStorage(bool renderTarget)
611{
612 // Only initialize the first time this texture is used as a render target or shader resource
613 if (mTexStorage)
614 {
615 return;
616 }
617
618 // do not attempt to create storage for nonexistant data
619 if (!isLevelComplete(0))
620 {
621 return;
622 }
623
624 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
625
626 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
627 ASSERT(mTexStorage);
628
629 // flush image data to the storage
630 updateStorage();
631}
632
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400633TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634{
635 GLsizei width = getBaseLevelWidth();
636 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400637 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638
639 ASSERT(width > 0 && height > 0);
640
641 // use existing storage level count, when previously specified by TexStorage*D
642 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
643
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400644 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700645}
646
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400647void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700648{
649 SafeDelete(mTexStorage);
650 mTexStorage = newCompleteTexStorage;
651
652 if (mTexStorage && mTexStorage->isManaged())
653 {
654 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
655 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400656 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700657 }
658 }
659
660 mDirtyImages = true;
661}
662
663void TextureD3D_2D::updateStorage()
664{
665 ASSERT(mTexStorage != NULL);
666 GLint storageLevels = mTexStorage->getLevelCount();
667 for (int level = 0; level < storageLevels; level++)
668 {
669 if (mImageArray[level]->isDirty() && isLevelComplete(level))
670 {
671 updateStorageLevel(level);
672 }
673 }
674}
675
676bool TextureD3D_2D::ensureRenderTarget()
677{
678 initializeStorage(true);
679
680 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
681 {
682 ASSERT(mTexStorage);
683 if (!mTexStorage->isRenderTarget())
684 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400685 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686
Geoff Lang9e3f24f2014-08-27 12:06:04 -0400687 if (mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688 {
689 delete newRenderTargetStorage;
690 return gl::error(GL_OUT_OF_MEMORY, false);
691 }
692
693 setCompleteTexStorage(newRenderTargetStorage);
694 }
695 }
696
697 return (mTexStorage && mTexStorage->isRenderTarget());
698}
699
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400700TextureStorage *TextureD3D_2D::getBaseLevelStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700701{
702 return mTexStorage;
703}
704
705const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
706{
707 return mImageArray[0];
708}
709
710void TextureD3D_2D::updateStorageLevel(int level)
711{
712 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
713 ASSERT(isLevelComplete(level));
714
715 if (mImageArray[level]->isDirty())
716 {
717 commitRect(level, 0, 0, getWidth(level), getHeight(level));
718 }
719}
720
721void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
722{
723 // If there currently is a corresponding storage texture image, it has these parameters
724 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
725 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
726 const GLenum storageFormat = getBaseLevelInternalFormat();
727
728 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
729
730 if (mTexStorage)
731 {
732 const int storageLevels = mTexStorage->getLevelCount();
733
734 if ((level >= storageLevels && storageLevels != 0) ||
735 width != storageWidth ||
736 height != storageHeight ||
737 internalformat != storageFormat) // Discard mismatched storage
738 {
739 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
740 {
741 mImageArray[i]->markDirty();
742 }
743
744 SafeDelete(mTexStorage);
745 mDirtyImages = true;
746 }
747 }
748}
749
750void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
751{
752 if (isValidLevel(level))
753 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700754 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -0400755 if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700756 {
757 image->markClean();
758 }
759 }
760}
761
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400762gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
763{
764 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
765}
Brandon Jones0511e802014-07-14 16:27:26 -0700766
Jamie Madillcb83dc12014-09-29 10:46:12 -0400767gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
768{
769 // "layer" does not apply to 2D Textures.
770 return gl::ImageIndex::Make2D(mip);
771}
772
Brandon Jones78b1acd2014-07-15 15:33:07 -0700773TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700774 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700775 mTexStorage(NULL)
776{
777 for (int i = 0; i < 6; i++)
778 {
779 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
780 {
781 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
782 }
783 }
784}
785
786TextureD3D_Cube::~TextureD3D_Cube()
787{
Austin Kinross69822602014-08-12 15:51:37 -0700788 // Delete the Images before the TextureStorage.
789 // Images might be relying on the TextureStorage for some of their data.
790 // 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 -0700791 for (int i = 0; i < 6; i++)
792 {
793 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
794 {
795 SafeDelete(mImageArray[i][j]);
796 }
797 }
Austin Kinross69822602014-08-12 15:51:37 -0700798
799 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700800}
801
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700803{
804 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700805 ASSERT(layer < 6);
806 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700807}
808
Jamie Madillfeda4d22014-09-17 13:03:29 -0400809Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
810{
811 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
812 ASSERT(index.layerIndex < 6);
813 return mImageArray[index.layerIndex][index.mipIndex];
814}
815
Brandon Jonescef06ff2014-08-05 13:27:48 -0700816GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700817{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700818 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
819 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700820}
821
Brandon Jonescef06ff2014-08-05 13:27:48 -0700822GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700823{
824 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700825 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700826 else
827 return GL_NONE;
828}
829
Brandon Jonescef06ff2014-08-05 13:27:48 -0700830bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700831{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700832 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700833}
834
Brandon Jonescef06ff2014-08-05 13:27:48 -0700835void 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 -0700836{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700837 ASSERT(depth == 1);
838
839 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400840 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700841
842 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
843
844 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
845}
846
Brandon Jonescef06ff2014-08-05 13:27:48 -0700847void 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 -0700848{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700849 ASSERT(depth == 1);
850
Brandon Jones0511e802014-07-14 16:27:26 -0700851 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700852 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
853
Brandon Jones0511e802014-07-14 16:27:26 -0700854 redefineImage(faceIndex, level, format, width, height);
855
856 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
857}
858
Brandon Jonescef06ff2014-08-05 13:27:48 -0700859void 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 -0700860{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700861 ASSERT(depth == 1 && zoffset == 0);
862
863 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
864
Jamie Madillfeda4d22014-09-17 13:03:29 -0400865 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
866 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700867 {
868 commitRect(faceIndex, level, xoffset, yoffset, width, height);
869 }
870}
871
Brandon Jonescef06ff2014-08-05 13:27:48 -0700872void 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 -0700873{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700874 ASSERT(depth == 1 && zoffset == 0);
875
876 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
877
Brandon Jones0511e802014-07-14 16:27:26 -0700878 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
879 {
880 commitRect(faceIndex, level, xoffset, yoffset, width, height);
881 }
882}
883
884void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
885{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700886 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400887 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
888
Brandon Jones0511e802014-07-14 16:27:26 -0700889 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
890
891 if (!mImageArray[faceIndex][level]->isRenderableFormat())
892 {
893 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
894 mDirtyImages = true;
895 }
896 else
897 {
898 ensureRenderTarget();
899 mImageArray[faceIndex][level]->markClean();
900
901 ASSERT(width == height);
902
903 if (width > 0 && isValidFaceLevel(faceIndex, level))
904 {
905 gl::Rectangle sourceRect;
906 sourceRect.x = x;
907 sourceRect.width = width;
908 sourceRect.y = y;
909 sourceRect.height = height;
910
Jamie Madill856d9d42014-09-18 15:08:49 -0400911 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700912 }
913 }
914}
915
916void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
917{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700918 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700919
920 // We can only make our texture storage to a render target if the level we're copying *to* is complete
921 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
922 // rely on the "getBaseLevel*" methods reliably otherwise.
923 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
924
925 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
926 {
927 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
928 mDirtyImages = true;
929 }
930 else
931 {
932 ensureRenderTarget();
933
934 if (isValidFaceLevel(faceIndex, level))
935 {
936 updateStorageFaceLevel(faceIndex, level);
937
938 gl::Rectangle sourceRect;
939 sourceRect.x = x;
940 sourceRect.width = width;
941 sourceRect.y = y;
942 sourceRect.height = height;
943
Jamie Madill856d9d42014-09-18 15:08:49 -0400944 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
945 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700946 }
947 }
948}
949
Brandon Jonescef06ff2014-08-05 13:27:48 -0700950void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700951{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700952 ASSERT(width == height);
953 ASSERT(depth == 1);
954
Brandon Jones0511e802014-07-14 16:27:26 -0700955 for (int level = 0; level < levels; level++)
956 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700957 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700958 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
959 {
960 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
961 }
962 }
963
964 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
965 {
966 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
967 {
968 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
969 }
970 }
971
972 mImmutable = true;
973
Jamie Madillc4833262014-09-18 16:18:26 -0400974 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400975 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
976 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -0700977}
978
Brandon Jones0511e802014-07-14 16:27:26 -0700979// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
980bool TextureD3D_Cube::isCubeComplete() const
981{
982 int baseWidth = getBaseLevelWidth();
983 int baseHeight = getBaseLevelHeight();
984 GLenum baseFormat = getBaseLevelInternalFormat();
985
986 if (baseWidth <= 0 || baseWidth != baseHeight)
987 {
988 return false;
989 }
990
991 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
992 {
993 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
994
995 if (faceBaseImage.getWidth() != baseWidth ||
996 faceBaseImage.getHeight() != baseHeight ||
997 faceBaseImage.getInternalFormat() != baseFormat )
998 {
999 return false;
1000 }
1001 }
1002
1003 return true;
1004}
1005
Brandon Jones6053a522014-07-25 16:22:09 -07001006void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1007{
1008 UNREACHABLE();
1009}
1010
1011void TextureD3D_Cube::releaseTexImage()
1012{
1013 UNREACHABLE();
1014}
1015
1016
Jamie Madill4aa79e12014-09-29 10:46:14 -04001017void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001018{
1019 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1020 int levelCount = mipLevels();
1021 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1022 {
1023 for (int level = 1; level < levelCount; level++)
1024 {
1025 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1026 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1027 }
1028 }
Brandon Jones0511e802014-07-14 16:27:26 -07001029}
1030
Jamie Madillac7579c2014-09-17 16:59:33 -04001031unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001032{
Jamie Madillc4833262014-09-18 16:18:26 -04001033 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001034}
1035
Jamie Madillac7579c2014-09-17 16:59:33 -04001036RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001037{
Jamie Madillac7579c2014-09-17 16:59:33 -04001038 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001039
1040 // ensure the underlying texture is created
1041 if (!ensureRenderTarget())
1042 {
1043 return NULL;
1044 }
1045
Jamie Madillac7579c2014-09-17 16:59:33 -04001046 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001047 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001048}
1049
Brandon Jones0511e802014-07-14 16:27:26 -07001050void TextureD3D_Cube::initializeStorage(bool renderTarget)
1051{
1052 // Only initialize the first time this texture is used as a render target or shader resource
1053 if (mTexStorage)
1054 {
1055 return;
1056 }
1057
1058 // do not attempt to create storage for nonexistant data
1059 if (!isFaceLevelComplete(0, 0))
1060 {
1061 return;
1062 }
1063
1064 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1065
1066 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1067 ASSERT(mTexStorage);
1068
1069 // flush image data to the storage
1070 updateStorage();
1071}
1072
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001073TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001074{
1075 GLsizei size = getBaseLevelWidth();
1076
1077 ASSERT(size > 0);
1078
1079 // use existing storage level count, when previously specified by TexStorage*D
1080 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1081
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001082 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001083}
1084
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001085void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001086{
1087 SafeDelete(mTexStorage);
1088 mTexStorage = newCompleteTexStorage;
1089
1090 if (mTexStorage && mTexStorage->isManaged())
1091 {
1092 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1093 {
1094 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1095 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001096 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001097 }
1098 }
1099 }
1100
1101 mDirtyImages = true;
1102}
1103
1104void TextureD3D_Cube::updateStorage()
1105{
1106 ASSERT(mTexStorage != NULL);
1107 GLint storageLevels = mTexStorage->getLevelCount();
1108 for (int face = 0; face < 6; face++)
1109 {
1110 for (int level = 0; level < storageLevels; level++)
1111 {
1112 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1113 {
1114 updateStorageFaceLevel(face, level);
1115 }
1116 }
1117 }
1118}
1119
1120bool TextureD3D_Cube::ensureRenderTarget()
1121{
1122 initializeStorage(true);
1123
1124 if (getBaseLevelWidth() > 0)
1125 {
1126 ASSERT(mTexStorage);
1127 if (!mTexStorage->isRenderTarget())
1128 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001129 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001130
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001131 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001132 {
1133 delete newRenderTargetStorage;
1134 return gl::error(GL_OUT_OF_MEMORY, false);
1135 }
1136
1137 setCompleteTexStorage(newRenderTargetStorage);
1138 }
1139 }
1140
1141 return (mTexStorage && mTexStorage->isRenderTarget());
1142}
1143
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001144TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001145{
1146 return mTexStorage;
1147}
1148
1149const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1150{
1151 // Note: if we are not cube-complete, there is no single base level image that can describe all
1152 // cube faces, so this method is only well-defined for a cube-complete base level.
1153 return mImageArray[0][0];
1154}
1155
Brandon Jones0511e802014-07-14 16:27:26 -07001156bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1157{
1158 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1159}
1160
Brandon Jones0511e802014-07-14 16:27:26 -07001161bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1162{
1163 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1164
1165 if (isImmutable())
1166 {
1167 return true;
1168 }
1169
1170 int baseSize = getBaseLevelWidth();
1171
1172 if (baseSize <= 0)
1173 {
1174 return false;
1175 }
1176
1177 // "isCubeComplete" checks for base level completeness and we must call that
1178 // to determine if any face at level 0 is complete. We omit that check here
1179 // to avoid re-checking cube-completeness for every face at level 0.
1180 if (level == 0)
1181 {
1182 return true;
1183 }
1184
1185 // Check that non-zero levels are consistent with the base level.
1186 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1187
1188 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1189 {
1190 return false;
1191 }
1192
1193 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1194 {
1195 return false;
1196 }
1197
1198 return true;
1199}
1200
1201void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1202{
1203 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1204 ImageD3D *image = mImageArray[faceIndex][level];
1205
1206 if (image->isDirty())
1207 {
1208 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1209 }
1210}
1211
1212void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1213{
1214 // If there currently is a corresponding storage texture image, it has these parameters
1215 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1216 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1217 const GLenum storageFormat = getBaseLevelInternalFormat();
1218
1219 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1220
1221 if (mTexStorage)
1222 {
1223 const int storageLevels = mTexStorage->getLevelCount();
1224
1225 if ((level >= storageLevels && storageLevels != 0) ||
1226 width != storageWidth ||
1227 height != storageHeight ||
1228 internalformat != storageFormat) // Discard mismatched storage
1229 {
1230 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1231 {
1232 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1233 {
1234 mImageArray[faceIndex][level]->markDirty();
1235 }
1236 }
1237
1238 SafeDelete(mTexStorage);
1239
1240 mDirtyImages = true;
1241 }
1242 }
1243}
1244
1245void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1246{
1247 if (isValidFaceLevel(faceIndex, level))
1248 {
1249 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001250 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001251 image->markClean();
1252 }
1253}
1254
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001255gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1256{
1257 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1258}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001259
Jamie Madillcb83dc12014-09-29 10:46:12 -04001260gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1261{
1262 // The "layer" of the image index corresponds to the cube face
1263 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1264}
1265
Brandon Jones78b1acd2014-07-15 15:33:07 -07001266TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001267 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001268 mTexStorage(NULL)
1269{
1270 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1271 {
1272 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1273 }
1274}
1275
1276TextureD3D_3D::~TextureD3D_3D()
1277{
Austin Kinross69822602014-08-12 15:51:37 -07001278 // Delete the Images before the TextureStorage.
1279 // Images might be relying on the TextureStorage for some of their data.
1280 // 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 -07001281 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1282 {
1283 delete mImageArray[i];
1284 }
Austin Kinross69822602014-08-12 15:51:37 -07001285
1286 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001287}
1288
Brandon Jonescef06ff2014-08-05 13:27:48 -07001289Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001290{
1291 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001292 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001293 return mImageArray[level];
1294}
1295
Jamie Madillfeda4d22014-09-17 13:03:29 -04001296Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1297{
1298 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001299 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001300 ASSERT(index.type == GL_TEXTURE_3D);
1301 return mImageArray[index.mipIndex];
1302}
1303
Brandon Jonescef06ff2014-08-05 13:27:48 -07001304GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001305{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001306 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1307 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001308}
1309
Brandon Jones78b1acd2014-07-15 15:33:07 -07001310GLsizei TextureD3D_3D::getWidth(GLint level) const
1311{
1312 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1313 return mImageArray[level]->getWidth();
1314 else
1315 return 0;
1316}
1317
1318GLsizei TextureD3D_3D::getHeight(GLint level) const
1319{
1320 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1321 return mImageArray[level]->getHeight();
1322 else
1323 return 0;
1324}
1325
1326GLsizei TextureD3D_3D::getDepth(GLint level) const
1327{
1328 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1329 return mImageArray[level]->getDepth();
1330 else
1331 return 0;
1332}
1333
1334GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1335{
1336 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1337 return mImageArray[level]->getInternalFormat();
1338 else
1339 return GL_NONE;
1340}
1341
1342bool TextureD3D_3D::isDepth(GLint level) const
1343{
Geoff Lang5d601382014-07-22 15:14:06 -04001344 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001345}
1346
Brandon Jonescef06ff2014-08-05 13:27:48 -07001347void 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 -07001348{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001349 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001350 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1351
Brandon Jones78b1acd2014-07-15 15:33:07 -07001352 redefineImage(level, sizedInternalFormat, width, height, depth);
1353
1354 bool fastUnpacked = false;
1355
1356 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1357 if (isFastUnpackable(unpack, sizedInternalFormat))
1358 {
1359 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001360 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1361 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001362 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1363
1364 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1365 {
1366 // Ensure we don't overwrite our newly initialized data
1367 mImageArray[level]->markClean();
1368
1369 fastUnpacked = true;
1370 }
1371 }
1372
1373 if (!fastUnpacked)
1374 {
1375 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1376 }
1377}
1378
Brandon Jonescef06ff2014-08-05 13:27:48 -07001379void 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 -07001380{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001381 ASSERT(target == GL_TEXTURE_3D);
1382
Brandon Jones78b1acd2014-07-15 15:33:07 -07001383 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1384 redefineImage(level, format, width, height, depth);
1385
1386 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1387}
1388
Brandon Jonescef06ff2014-08-05 13:27:48 -07001389void 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 -07001390{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001391 ASSERT(target == GL_TEXTURE_3D);
1392
Brandon Jones78b1acd2014-07-15 15:33:07 -07001393 bool fastUnpacked = false;
1394
Jamie Madillac7579c2014-09-17 16:59:33 -04001395 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1396
Brandon Jones78b1acd2014-07-15 15:33:07 -07001397 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1398 if (isFastUnpackable(unpack, getInternalFormat(level)))
1399 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001400 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001401 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1402
1403 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1404 {
1405 // Ensure we don't overwrite our newly initialized data
1406 mImageArray[level]->markClean();
1407
1408 fastUnpacked = true;
1409 }
1410 }
1411
Jamie Madillfeda4d22014-09-17 13:03:29 -04001412 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413 {
1414 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1415 }
1416}
1417
Brandon Jonescef06ff2014-08-05 13:27:48 -07001418void 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 -07001419{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001420 ASSERT(target == GL_TEXTURE_3D);
1421
Brandon Jones78b1acd2014-07-15 15:33:07 -07001422 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1423 {
1424 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1425 }
1426}
1427
Brandon Jonescef06ff2014-08-05 13:27:48 -07001428void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1429{
1430 UNIMPLEMENTED();
1431}
1432
Brandon Jones78b1acd2014-07-15 15:33:07 -07001433void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1434{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001435 ASSERT(target == GL_TEXTURE_3D);
1436
Brandon Jones78b1acd2014-07-15 15:33:07 -07001437 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1438 // the current level we're copying to is defined (with appropriate format, width & height)
1439 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1440
1441 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1442 {
1443 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1444 mDirtyImages = true;
1445 }
1446 else
1447 {
1448 ensureRenderTarget();
1449
1450 if (isValidLevel(level))
1451 {
1452 updateStorageLevel(level);
1453
1454 gl::Rectangle sourceRect;
1455 sourceRect.x = x;
1456 sourceRect.width = width;
1457 sourceRect.y = y;
1458 sourceRect.height = height;
1459
Jamie Madill856d9d42014-09-18 15:08:49 -04001460 mRenderer->copyImage3D(source, sourceRect,
1461 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1462 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001463 }
1464 }
1465}
1466
Brandon Jonescef06ff2014-08-05 13:27:48 -07001467void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001468{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001469 ASSERT(target == GL_TEXTURE_3D);
1470
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471 for (int level = 0; level < levels; level++)
1472 {
1473 GLsizei levelWidth = std::max(1, width >> level);
1474 GLsizei levelHeight = std::max(1, height >> level);
1475 GLsizei levelDepth = std::max(1, depth >> level);
1476 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1477 }
1478
1479 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1480 {
1481 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1482 }
1483
1484 mImmutable = true;
1485
Jamie Madillc4833262014-09-18 16:18:26 -04001486 bool renderTarget = IsRenderTargetUsage(mUsage);
1487 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001488 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001489}
1490
Brandon Jones6053a522014-07-25 16:22:09 -07001491void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001492{
Brandon Jones6053a522014-07-25 16:22:09 -07001493 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001494}
1495
Brandon Jones6053a522014-07-25 16:22:09 -07001496void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001497{
Brandon Jones6053a522014-07-25 16:22:09 -07001498 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001499}
1500
Brandon Jones6053a522014-07-25 16:22:09 -07001501
Jamie Madill4aa79e12014-09-29 10:46:14 -04001502void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503{
1504 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1505 int levelCount = mipLevels();
1506 for (int level = 1; level < levelCount; level++)
1507 {
1508 redefineImage(level, getBaseLevelInternalFormat(),
1509 std::max(getBaseLevelWidth() >> level, 1),
1510 std::max(getBaseLevelHeight() >> level, 1),
1511 std::max(getBaseLevelDepth() >> level, 1));
1512 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001513}
1514
Jamie Madillac7579c2014-09-17 16:59:33 -04001515unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516{
Jamie Madillc4833262014-09-18 16:18:26 -04001517 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001518}
1519
Jamie Madillac7579c2014-09-17 16:59:33 -04001520RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001521{
1522 // ensure the underlying texture is created
1523 if (!ensureRenderTarget())
1524 {
1525 return NULL;
1526 }
1527
Jamie Madillac7579c2014-09-17 16:59:33 -04001528 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001529 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001530 updateStorage();
1531 }
1532 else
1533 {
1534 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535 }
1536
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001537 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001538}
1539
1540void TextureD3D_3D::initializeStorage(bool renderTarget)
1541{
1542 // Only initialize the first time this texture is used as a render target or shader resource
1543 if (mTexStorage)
1544 {
1545 return;
1546 }
1547
1548 // do not attempt to create storage for nonexistant data
1549 if (!isLevelComplete(0))
1550 {
1551 return;
1552 }
1553
1554 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1555
1556 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1557 ASSERT(mTexStorage);
1558
1559 // flush image data to the storage
1560 updateStorage();
1561}
1562
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001563TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001564{
1565 GLsizei width = getBaseLevelWidth();
1566 GLsizei height = getBaseLevelHeight();
1567 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001568 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001569
1570 ASSERT(width > 0 && height > 0 && depth > 0);
1571
1572 // use existing storage level count, when previously specified by TexStorage*D
1573 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1574
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001575 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001576}
1577
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001578void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001579{
1580 SafeDelete(mTexStorage);
1581 mTexStorage = newCompleteTexStorage;
1582 mDirtyImages = true;
1583
1584 // We do not support managed 3D storage, as that is D3D9/ES2-only
1585 ASSERT(!mTexStorage->isManaged());
1586}
1587
1588void TextureD3D_3D::updateStorage()
1589{
1590 ASSERT(mTexStorage != NULL);
1591 GLint storageLevels = mTexStorage->getLevelCount();
1592 for (int level = 0; level < storageLevels; level++)
1593 {
1594 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1595 {
1596 updateStorageLevel(level);
1597 }
1598 }
1599}
1600
1601bool TextureD3D_3D::ensureRenderTarget()
1602{
1603 initializeStorage(true);
1604
1605 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1606 {
1607 ASSERT(mTexStorage);
1608 if (!mTexStorage->isRenderTarget())
1609 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001610 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001611
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001612 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001613 {
1614 delete newRenderTargetStorage;
1615 return gl::error(GL_OUT_OF_MEMORY, false);
1616 }
1617
1618 setCompleteTexStorage(newRenderTargetStorage);
1619 }
1620 }
1621
1622 return (mTexStorage && mTexStorage->isRenderTarget());
1623}
1624
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001625TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626{
1627 return mTexStorage;
1628}
1629
1630const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1631{
1632 return mImageArray[0];
1633}
1634
1635bool TextureD3D_3D::isValidLevel(int level) const
1636{
1637 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1638}
1639
1640bool TextureD3D_3D::isLevelComplete(int level) const
1641{
1642 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1643
1644 if (isImmutable())
1645 {
1646 return true;
1647 }
1648
1649 GLsizei width = getBaseLevelWidth();
1650 GLsizei height = getBaseLevelHeight();
1651 GLsizei depth = getBaseLevelDepth();
1652
1653 if (width <= 0 || height <= 0 || depth <= 0)
1654 {
1655 return false;
1656 }
1657
1658 if (level == 0)
1659 {
1660 return true;
1661 }
1662
1663 ImageD3D *levelImage = mImageArray[level];
1664
1665 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1666 {
1667 return false;
1668 }
1669
1670 if (levelImage->getWidth() != std::max(1, width >> level))
1671 {
1672 return false;
1673 }
1674
1675 if (levelImage->getHeight() != std::max(1, height >> level))
1676 {
1677 return false;
1678 }
1679
1680 if (levelImage->getDepth() != std::max(1, depth >> level))
1681 {
1682 return false;
1683 }
1684
1685 return true;
1686}
1687
1688void TextureD3D_3D::updateStorageLevel(int level)
1689{
1690 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1691 ASSERT(isLevelComplete(level));
1692
1693 if (mImageArray[level]->isDirty())
1694 {
1695 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1696 }
1697}
1698
1699void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1700{
1701 // If there currently is a corresponding storage texture image, it has these parameters
1702 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1703 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1704 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1705 const GLenum storageFormat = getBaseLevelInternalFormat();
1706
1707 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1708
1709 if (mTexStorage)
1710 {
1711 const int storageLevels = mTexStorage->getLevelCount();
1712
1713 if ((level >= storageLevels && storageLevels != 0) ||
1714 width != storageWidth ||
1715 height != storageHeight ||
1716 depth != storageDepth ||
1717 internalformat != storageFormat) // Discard mismatched storage
1718 {
1719 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1720 {
1721 mImageArray[i]->markDirty();
1722 }
1723
1724 SafeDelete(mTexStorage);
1725 mDirtyImages = true;
1726 }
1727 }
1728}
1729
1730void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1731{
1732 if (isValidLevel(level))
1733 {
1734 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001735 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001736 {
1737 image->markClean();
1738 }
1739 }
1740}
1741
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001742gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1743{
1744 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1745 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1746}
Brandon Jones142ec422014-07-16 10:31:30 -07001747
Jamie Madillcb83dc12014-09-29 10:46:12 -04001748gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1749{
1750 // The "layer" here does not apply to 3D images. We use one Image per mip.
1751 return gl::ImageIndex::Make3D(mip);
1752}
1753
Brandon Jones142ec422014-07-16 10:31:30 -07001754TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001755 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001756 mTexStorage(NULL)
1757{
1758 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1759 {
1760 mLayerCounts[level] = 0;
1761 mImageArray[level] = NULL;
1762 }
1763}
1764
1765TextureD3D_2DArray::~TextureD3D_2DArray()
1766{
Austin Kinross69822602014-08-12 15:51:37 -07001767 // Delete the Images before the TextureStorage.
1768 // Images might be relying on the TextureStorage for some of their data.
1769 // 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 -07001770 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001771 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001772}
1773
Brandon Jones142ec422014-07-16 10:31:30 -07001774Image *TextureD3D_2DArray::getImage(int level, int layer) const
1775{
1776 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1777 ASSERT(layer < mLayerCounts[level]);
1778 return mImageArray[level][layer];
1779}
1780
Jamie Madillfeda4d22014-09-17 13:03:29 -04001781Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1782{
1783 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1784 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1785 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1786 return mImageArray[index.mipIndex][index.layerIndex];
1787}
1788
Brandon Jones142ec422014-07-16 10:31:30 -07001789GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1790{
1791 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1792 return mLayerCounts[level];
1793}
1794
Brandon Jones142ec422014-07-16 10:31:30 -07001795GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1796{
1797 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1798}
1799
1800GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1801{
1802 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1803}
1804
1805GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1806{
1807 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1808}
1809
1810GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1811{
1812 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1813}
1814
1815bool TextureD3D_2DArray::isDepth(GLint level) const
1816{
Geoff Lang5d601382014-07-22 15:14:06 -04001817 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001818}
1819
Brandon Jonescef06ff2014-08-05 13:27:48 -07001820void 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 -07001821{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001822 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1823
Geoff Lang5d601382014-07-22 15:14:06 -04001824 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1825
Brandon Jones142ec422014-07-16 10:31:30 -07001826 redefineImage(level, sizedInternalFormat, width, height, depth);
1827
Geoff Lang5d601382014-07-22 15:14:06 -04001828 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1829 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001830
1831 for (int i = 0; i < depth; i++)
1832 {
1833 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1834 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1835 }
1836}
1837
Brandon Jonescef06ff2014-08-05 13:27:48 -07001838void 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 -07001839{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001840 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1841
Brandon Jones142ec422014-07-16 10:31:30 -07001842 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1843 redefineImage(level, format, width, height, depth);
1844
Geoff Lang5d601382014-07-22 15:14:06 -04001845 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1846 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001847
1848 for (int i = 0; i < depth; i++)
1849 {
1850 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1851 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1852 }
1853}
1854
Brandon Jonescef06ff2014-08-05 13:27:48 -07001855void 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 -07001856{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001857 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1858
Geoff Lang5d601382014-07-22 15:14:06 -04001859 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1860 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001861
1862 for (int i = 0; i < depth; i++)
1863 {
1864 int layer = zoffset + i;
1865 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1866
Jamie Madillfeda4d22014-09-17 13:03:29 -04001867 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1868 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001869 {
1870 commitRect(level, xoffset, yoffset, layer, width, height);
1871 }
1872 }
1873}
1874
Brandon Jonescef06ff2014-08-05 13:27:48 -07001875void 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 -07001876{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001877 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1878
Geoff Lang5d601382014-07-22 15:14:06 -04001879 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1880 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001881
1882 for (int i = 0; i < depth; i++)
1883 {
1884 int layer = zoffset + i;
1885 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1886
1887 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1888 {
1889 commitRect(level, xoffset, yoffset, layer, width, height);
1890 }
1891 }
1892}
1893
Brandon Jonescef06ff2014-08-05 13:27:48 -07001894void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1895{
1896 UNIMPLEMENTED();
1897}
1898
Brandon Jones142ec422014-07-16 10:31:30 -07001899void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1900{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001901 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1902
Brandon Jones142ec422014-07-16 10:31:30 -07001903 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1904 // the current level we're copying to is defined (with appropriate format, width & height)
1905 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1906
1907 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1908 {
1909 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1910 mDirtyImages = true;
1911 }
1912 else
1913 {
1914 ensureRenderTarget();
1915
1916 if (isValidLevel(level))
1917 {
1918 updateStorageLevel(level);
1919
1920 gl::Rectangle sourceRect;
1921 sourceRect.x = x;
1922 sourceRect.width = width;
1923 sourceRect.y = y;
1924 sourceRect.height = height;
1925
Jamie Madill856d9d42014-09-18 15:08:49 -04001926 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1927 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001928 }
1929 }
1930}
1931
Brandon Jonescef06ff2014-08-05 13:27:48 -07001932void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001933{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001934 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1935
Brandon Jones142ec422014-07-16 10:31:30 -07001936 deleteImages();
1937
1938 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1939 {
1940 GLsizei levelWidth = std::max(1, width >> level);
1941 GLsizei levelHeight = std::max(1, height >> level);
1942
1943 mLayerCounts[level] = (level < levels ? depth : 0);
1944
1945 if (mLayerCounts[level] > 0)
1946 {
1947 // Create new images for this level
1948 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1949
1950 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1951 {
1952 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1953 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1954 levelHeight, 1, true);
1955 }
1956 }
1957 }
1958
1959 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001960
1961 bool renderTarget = IsRenderTargetUsage(mUsage);
1962 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001963 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07001964}
1965
Brandon Jones6053a522014-07-25 16:22:09 -07001966void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001967{
Brandon Jones6053a522014-07-25 16:22:09 -07001968 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001969}
1970
Brandon Jones6053a522014-07-25 16:22:09 -07001971void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001972{
Brandon Jones6053a522014-07-25 16:22:09 -07001973 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001974}
1975
Brandon Jones6053a522014-07-25 16:22:09 -07001976
Jamie Madill4aa79e12014-09-29 10:46:14 -04001977void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07001978{
1979 int baseWidth = getBaseLevelWidth();
1980 int baseHeight = getBaseLevelHeight();
1981 int baseDepth = getBaseLevelDepth();
1982 GLenum baseFormat = getBaseLevelInternalFormat();
1983
1984 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1985 int levelCount = mipLevels();
1986 for (int level = 1; level < levelCount; level++)
1987 {
1988 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1989 }
Brandon Jones142ec422014-07-16 10:31:30 -07001990}
1991
Jamie Madillac7579c2014-09-17 16:59:33 -04001992unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07001993{
Jamie Madillc4833262014-09-18 16:18:26 -04001994 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07001995}
1996
Jamie Madillac7579c2014-09-17 16:59:33 -04001997RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07001998{
1999 // ensure the underlying texture is created
2000 if (!ensureRenderTarget())
2001 {
2002 return NULL;
2003 }
2004
Jamie Madillac7579c2014-09-17 16:59:33 -04002005 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002006 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002007}
2008
2009void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2010{
2011 // Only initialize the first time this texture is used as a render target or shader resource
2012 if (mTexStorage)
2013 {
2014 return;
2015 }
2016
2017 // do not attempt to create storage for nonexistant data
2018 if (!isLevelComplete(0))
2019 {
2020 return;
2021 }
2022
2023 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2024
2025 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2026 ASSERT(mTexStorage);
2027
2028 // flush image data to the storage
2029 updateStorage();
2030}
2031
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002032TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002033{
2034 GLsizei width = getBaseLevelWidth();
2035 GLsizei height = getBaseLevelHeight();
2036 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002037 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002038
2039 ASSERT(width > 0 && height > 0 && depth > 0);
2040
2041 // use existing storage level count, when previously specified by TexStorage*D
2042 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2043
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002044 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002045}
2046
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002047void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002048{
2049 SafeDelete(mTexStorage);
2050 mTexStorage = newCompleteTexStorage;
2051 mDirtyImages = true;
2052
2053 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2054 ASSERT(!mTexStorage->isManaged());
2055}
2056
2057void TextureD3D_2DArray::updateStorage()
2058{
2059 ASSERT(mTexStorage != NULL);
2060 GLint storageLevels = mTexStorage->getLevelCount();
2061 for (int level = 0; level < storageLevels; level++)
2062 {
2063 if (isLevelComplete(level))
2064 {
2065 updateStorageLevel(level);
2066 }
2067 }
2068}
2069
2070bool TextureD3D_2DArray::ensureRenderTarget()
2071{
2072 initializeStorage(true);
2073
2074 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2075 {
2076 ASSERT(mTexStorage);
2077 if (!mTexStorage->isRenderTarget())
2078 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002079 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002080
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002081 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002082 {
2083 delete newRenderTargetStorage;
2084 return gl::error(GL_OUT_OF_MEMORY, false);
2085 }
2086
2087 setCompleteTexStorage(newRenderTargetStorage);
2088 }
2089 }
2090
2091 return (mTexStorage && mTexStorage->isRenderTarget());
2092}
2093
2094const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2095{
2096 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2097}
2098
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002099TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002100{
2101 return mTexStorage;
2102}
2103
2104bool TextureD3D_2DArray::isValidLevel(int level) const
2105{
2106 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2107}
2108
2109bool TextureD3D_2DArray::isLevelComplete(int level) const
2110{
2111 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2112
2113 if (isImmutable())
2114 {
2115 return true;
2116 }
2117
2118 GLsizei width = getBaseLevelWidth();
2119 GLsizei height = getBaseLevelHeight();
2120 GLsizei layers = getLayers(0);
2121
2122 if (width <= 0 || height <= 0 || layers <= 0)
2123 {
2124 return false;
2125 }
2126
2127 if (level == 0)
2128 {
2129 return true;
2130 }
2131
2132 if (getInternalFormat(level) != getInternalFormat(0))
2133 {
2134 return false;
2135 }
2136
2137 if (getWidth(level) != std::max(1, width >> level))
2138 {
2139 return false;
2140 }
2141
2142 if (getHeight(level) != std::max(1, height >> level))
2143 {
2144 return false;
2145 }
2146
2147 if (getLayers(level) != layers)
2148 {
2149 return false;
2150 }
2151
2152 return true;
2153}
2154
2155void TextureD3D_2DArray::updateStorageLevel(int level)
2156{
2157 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2158 ASSERT(isLevelComplete(level));
2159
2160 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2161 {
2162 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2163 if (mImageArray[level][layer]->isDirty())
2164 {
2165 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2166 }
2167 }
2168}
2169
2170void TextureD3D_2DArray::deleteImages()
2171{
2172 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2173 {
2174 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2175 {
2176 delete mImageArray[level][layer];
2177 }
2178 delete[] mImageArray[level];
2179 mImageArray[level] = NULL;
2180 mLayerCounts[level] = 0;
2181 }
2182}
2183
2184void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2185{
2186 // If there currently is a corresponding storage texture image, it has these parameters
2187 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2188 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2189 const int storageDepth = getLayers(0);
2190 const GLenum storageFormat = getBaseLevelInternalFormat();
2191
2192 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2193 {
2194 delete mImageArray[level][layer];
2195 }
2196 delete[] mImageArray[level];
2197 mImageArray[level] = NULL;
2198 mLayerCounts[level] = depth;
2199
2200 if (depth > 0)
2201 {
2202 mImageArray[level] = new ImageD3D*[depth]();
2203
2204 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2205 {
2206 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2207 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2208 }
2209 }
2210
2211 if (mTexStorage)
2212 {
2213 const int storageLevels = mTexStorage->getLevelCount();
2214
2215 if ((level >= storageLevels && storageLevels != 0) ||
2216 width != storageWidth ||
2217 height != storageHeight ||
2218 depth != storageDepth ||
2219 internalformat != storageFormat) // Discard mismatched storage
2220 {
2221 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2222 {
2223 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2224 {
2225 mImageArray[level][layer]->markDirty();
2226 }
2227 }
2228
2229 delete mTexStorage;
2230 mTexStorage = NULL;
2231 mDirtyImages = true;
2232 }
2233 }
2234}
2235
2236void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2237{
2238 if (isValidLevel(level) && layerTarget < getLayers(level))
2239 {
2240 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002241 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002242 {
2243 image->markClean();
2244 }
2245 }
2246}
2247
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002248gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2249{
2250 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2251}
2252
Jamie Madillcb83dc12014-09-29 10:46:12 -04002253gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2254{
2255 return gl::ImageIndex::Make2DArray(mip, layer);
2256}
2257
Brandon Jones78b1acd2014-07-15 15:33:07 -07002258}