blob: a173b3bde0a5e3b73aae21bed28505049f667f65 [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
Geoff Langae5122c2014-08-27 14:08:43 -0400191 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
192 if (error.isError())
193 {
194 return false;
195 }
196
197 return true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198}
199
200GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
201{
202 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
203 {
204 // Maximum number of levels
205 return gl::log2(std::max(std::max(width, height), depth)) + 1;
206 }
207 else
208 {
209 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
210 return 1;
211 }
212}
213
214int TextureD3D::mipLevels() const
215{
216 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
217}
218
Jamie Madill4aa79e12014-09-29 10:46:14 -0400219void TextureD3D::generateMipmaps()
220{
221 // Set up proper image sizes.
222 initMipmapsImages();
223
224 // We know that all layers have the same dimension, for the texture to be complete
225 GLint layerCount = static_cast<GLint>(getLayerCount(0));
226 GLint mipCount = mipLevels();
227
228 // The following will create and initialize the storage, or update it if it exists
229 TextureStorage *storage = getNativeTexture();
230
231 bool renderableStorage = (storage && storage->isRenderTarget());
232
233 for (GLint layer = 0; layer < layerCount; ++layer)
234 {
235 for (GLint mip = 1; mip < mipCount; ++mip)
236 {
237 ASSERT(getLayerCount(mip) == layerCount);
238
239 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
240 gl::ImageIndex destIndex = getImageIndex(mip, layer);
241
242 if (renderableStorage)
243 {
244 // GPU-side mipmapping
245 storage->generateMipmap(sourceIndex, destIndex);
246 }
247 else
248 {
249 // CPU-side mipmapping
250 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
251 }
252 }
253 }
254}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700255
Brandon Jones78b1acd2014-07-15 15:33:07 -0700256TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700257 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258 mTexStorage(NULL)
259{
260 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
261 {
262 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
263 }
264}
265
266TextureD3D_2D::~TextureD3D_2D()
267{
Austin Kinross69822602014-08-12 15:51:37 -0700268 // Delete the Images before the TextureStorage.
269 // Images might be relying on the TextureStorage for some of their data.
270 // 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 -0700271 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
272 {
273 delete mImageArray[i];
274 }
Austin Kinross69822602014-08-12 15:51:37 -0700275
276 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700277}
278
Brandon Jonescef06ff2014-08-05 13:27:48 -0700279Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700280{
281 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700282 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700283 return mImageArray[level];
284}
285
Jamie Madillfeda4d22014-09-17 13:03:29 -0400286Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
287{
288 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400289 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400290 ASSERT(index.type == GL_TEXTURE_2D);
291 return mImageArray[index.mipIndex];
292}
293
Brandon Jonescef06ff2014-08-05 13:27:48 -0700294GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700295{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700296 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
297 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700298}
299
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700300GLsizei TextureD3D_2D::getWidth(GLint level) const
301{
302 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
303 return mImageArray[level]->getWidth();
304 else
305 return 0;
306}
307
308GLsizei TextureD3D_2D::getHeight(GLint level) const
309{
310 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
311 return mImageArray[level]->getHeight();
312 else
313 return 0;
314}
315
316GLenum TextureD3D_2D::getInternalFormat(GLint level) const
317{
318 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
319 return mImageArray[level]->getInternalFormat();
320 else
321 return GL_NONE;
322}
323
324GLenum TextureD3D_2D::getActualFormat(GLint level) const
325{
326 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
327 return mImageArray[level]->getActualFormat();
328 else
329 return GL_NONE;
330}
331
332bool TextureD3D_2D::isDepth(GLint level) const
333{
Geoff Lang5d601382014-07-22 15:14:06 -0400334 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700335}
336
Brandon Jonescef06ff2014-08-05 13:27:48 -0700337void 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 -0700338{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700339 ASSERT(target == GL_TEXTURE_2D && depth == 1);
340
Geoff Lang5d601382014-07-22 15:14:06 -0400341 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
342
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700343 bool fastUnpacked = false;
344
Brandon Jonescef06ff2014-08-05 13:27:48 -0700345 redefineImage(level, sizedInternalFormat, width, height);
346
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700347 // Attempt a fast gpu copy of the pixel data to the surface
348 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
349 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400350 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
351
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700352 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400353 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700354 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
355
356 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
357 {
358 // Ensure we don't overwrite our newly initialized data
359 mImageArray[level]->markClean();
360
361 fastUnpacked = true;
362 }
363 }
364
365 if (!fastUnpacked)
366 {
367 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
368 }
369}
370
Brandon Jonescef06ff2014-08-05 13:27:48 -0700371void 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 -0700372{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700373 ASSERT(target == GL_TEXTURE_2D && depth == 1);
374
375 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
376 redefineImage(level, format, width, height);
377
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700378 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
379}
380
Brandon Jonescef06ff2014-08-05 13:27:48 -0700381void 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 -0700382{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700383 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
384
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700385 bool fastUnpacked = false;
386
Jamie Madillac7579c2014-09-17 16:59:33 -0400387 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700388 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
389 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400390 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700391 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
392
393 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
394 {
395 // Ensure we don't overwrite our newly initialized data
396 mImageArray[level]->markClean();
397
398 fastUnpacked = true;
399 }
400 }
401
Jamie Madillfeda4d22014-09-17 13:03:29 -0400402 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700403 {
404 commitRect(level, xoffset, yoffset, width, height);
405 }
406}
407
Brandon Jonescef06ff2014-08-05 13:27:48 -0700408void 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 -0700409{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700410 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
411
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700412 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
413 {
414 commitRect(level, xoffset, yoffset, width, height);
415 }
416}
417
Brandon Jonescef06ff2014-08-05 13:27:48 -0700418void 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 -0700419{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700420 ASSERT(target == GL_TEXTURE_2D);
421
422 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
423 redefineImage(level, sizedInternalFormat, width, height);
424
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700425 if (!mImageArray[level]->isRenderableFormat())
426 {
427 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
428 mDirtyImages = true;
429 }
430 else
431 {
432 ensureRenderTarget();
433 mImageArray[level]->markClean();
434
435 if (width != 0 && height != 0 && isValidLevel(level))
436 {
437 gl::Rectangle sourceRect;
438 sourceRect.x = x;
439 sourceRect.width = width;
440 sourceRect.y = y;
441 sourceRect.height = height;
442
Jamie Madill856d9d42014-09-18 15:08:49 -0400443 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700444 }
445 }
446}
447
448void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
449{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700450 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
451
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700452 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
453 // the current level we're copying to is defined (with appropriate format, width & height)
454 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
455
456 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
457 {
458 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
459 mDirtyImages = true;
460 }
461 else
462 {
463 ensureRenderTarget();
464
465 if (isValidLevel(level))
466 {
467 updateStorageLevel(level);
468
469 gl::Rectangle sourceRect;
470 sourceRect.x = x;
471 sourceRect.width = width;
472 sourceRect.y = y;
473 sourceRect.height = height;
474
Jamie Madill856d9d42014-09-18 15:08:49 -0400475 mRenderer->copyImage2D(source, sourceRect,
476 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
477 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700478 }
479 }
480}
481
Brandon Jonescef06ff2014-08-05 13:27:48 -0700482void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700483{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700484 ASSERT(target == GL_TEXTURE_2D && depth == 1);
485
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700486 for (int level = 0; level < levels; level++)
487 {
488 GLsizei levelWidth = std::max(1, width >> level);
489 GLsizei levelHeight = std::max(1, height >> level);
490 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
491 }
492
493 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
494 {
495 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
496 }
497
498 mImmutable = true;
499
Jamie Madillc4833262014-09-18 16:18:26 -0400500 bool renderTarget = IsRenderTargetUsage(mUsage);
501 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400502 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503}
504
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505void TextureD3D_2D::bindTexImage(egl::Surface *surface)
506{
507 GLenum internalformat = surface->getFormat();
508
509 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
510
511 if (mTexStorage)
512 {
513 SafeDelete(mTexStorage);
514 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400515
516 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700517
518 mDirtyImages = true;
519}
520
521void TextureD3D_2D::releaseTexImage()
522{
523 if (mTexStorage)
524 {
525 SafeDelete(mTexStorage);
526 }
527
528 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
529 {
530 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
531 }
532}
533
Jamie Madill4aa79e12014-09-29 10:46:14 -0400534void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700536 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700537 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700538 for (int level = 1; level < levelCount; level++)
539 {
540 redefineImage(level, getBaseLevelInternalFormat(),
541 std::max(getBaseLevelWidth() >> level, 1),
542 std::max(getBaseLevelHeight() >> level, 1));
543 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700544}
545
Jamie Madillac7579c2014-09-17 16:59:33 -0400546unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700547{
Jamie Madillac7579c2014-09-17 16:59:33 -0400548 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400549 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700550}
551
Jamie Madillac7579c2014-09-17 16:59:33 -0400552RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700553{
Jamie Madillac7579c2014-09-17 16:59:33 -0400554 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700555
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700556 // ensure the underlying texture is created
557 if (!ensureRenderTarget())
558 {
559 return NULL;
560 }
561
Jamie Madillac7579c2014-09-17 16:59:33 -0400562 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400563 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700564}
565
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700566bool TextureD3D_2D::isValidLevel(int level) const
567{
568 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
569}
570
571bool TextureD3D_2D::isLevelComplete(int level) const
572{
573 if (isImmutable())
574 {
575 return true;
576 }
577
Brandon Jones78b1acd2014-07-15 15:33:07 -0700578 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579
580 GLsizei width = baseImage->getWidth();
581 GLsizei height = baseImage->getHeight();
582
583 if (width <= 0 || height <= 0)
584 {
585 return false;
586 }
587
588 // The base image level is complete if the width and height are positive
589 if (level == 0)
590 {
591 return true;
592 }
593
594 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700595 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596
597 if (image->getInternalFormat() != baseImage->getInternalFormat())
598 {
599 return false;
600 }
601
602 if (image->getWidth() != std::max(1, width >> level))
603 {
604 return false;
605 }
606
607 if (image->getHeight() != std::max(1, height >> level))
608 {
609 return false;
610 }
611
612 return true;
613}
614
615// Constructs a native texture resource from the texture images
616void TextureD3D_2D::initializeStorage(bool renderTarget)
617{
618 // Only initialize the first time this texture is used as a render target or shader resource
619 if (mTexStorage)
620 {
621 return;
622 }
623
624 // do not attempt to create storage for nonexistant data
625 if (!isLevelComplete(0))
626 {
627 return;
628 }
629
630 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
631
632 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
633 ASSERT(mTexStorage);
634
635 // flush image data to the storage
636 updateStorage();
637}
638
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400639TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700640{
641 GLsizei width = getBaseLevelWidth();
642 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400643 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700644
645 ASSERT(width > 0 && height > 0);
646
647 // use existing storage level count, when previously specified by TexStorage*D
648 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
649
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400650 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651}
652
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400653void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654{
655 SafeDelete(mTexStorage);
656 mTexStorage = newCompleteTexStorage;
657
658 if (mTexStorage && mTexStorage->isManaged())
659 {
660 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
661 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400662 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663 }
664 }
665
666 mDirtyImages = true;
667}
668
669void TextureD3D_2D::updateStorage()
670{
671 ASSERT(mTexStorage != NULL);
672 GLint storageLevels = mTexStorage->getLevelCount();
673 for (int level = 0; level < storageLevels; level++)
674 {
675 if (mImageArray[level]->isDirty() && isLevelComplete(level))
676 {
677 updateStorageLevel(level);
678 }
679 }
680}
681
682bool TextureD3D_2D::ensureRenderTarget()
683{
684 initializeStorage(true);
685
686 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
687 {
688 ASSERT(mTexStorage);
689 if (!mTexStorage->isRenderTarget())
690 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400691 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700692
Geoff Lang9e3f24f2014-08-27 12:06:04 -0400693 if (mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694 {
695 delete newRenderTargetStorage;
696 return gl::error(GL_OUT_OF_MEMORY, false);
697 }
698
699 setCompleteTexStorage(newRenderTargetStorage);
700 }
701 }
702
703 return (mTexStorage && mTexStorage->isRenderTarget());
704}
705
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400706TextureStorage *TextureD3D_2D::getBaseLevelStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700707{
708 return mTexStorage;
709}
710
711const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
712{
713 return mImageArray[0];
714}
715
716void TextureD3D_2D::updateStorageLevel(int level)
717{
718 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
719 ASSERT(isLevelComplete(level));
720
721 if (mImageArray[level]->isDirty())
722 {
723 commitRect(level, 0, 0, getWidth(level), getHeight(level));
724 }
725}
726
727void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
728{
729 // If there currently is a corresponding storage texture image, it has these parameters
730 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
731 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
732 const GLenum storageFormat = getBaseLevelInternalFormat();
733
734 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
735
736 if (mTexStorage)
737 {
738 const int storageLevels = mTexStorage->getLevelCount();
739
740 if ((level >= storageLevels && storageLevels != 0) ||
741 width != storageWidth ||
742 height != storageHeight ||
743 internalformat != storageFormat) // Discard mismatched storage
744 {
745 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
746 {
747 mImageArray[i]->markDirty();
748 }
749
750 SafeDelete(mTexStorage);
751 mDirtyImages = true;
752 }
753 }
754}
755
756void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
757{
758 if (isValidLevel(level))
759 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700760 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -0400761 if (image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700762 {
763 image->markClean();
764 }
765 }
766}
767
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400768gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
769{
770 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
771}
Brandon Jones0511e802014-07-14 16:27:26 -0700772
Jamie Madillcb83dc12014-09-29 10:46:12 -0400773gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
774{
775 // "layer" does not apply to 2D Textures.
776 return gl::ImageIndex::Make2D(mip);
777}
778
Brandon Jones78b1acd2014-07-15 15:33:07 -0700779TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700780 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700781 mTexStorage(NULL)
782{
783 for (int i = 0; i < 6; i++)
784 {
785 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
786 {
787 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
788 }
789 }
790}
791
792TextureD3D_Cube::~TextureD3D_Cube()
793{
Austin Kinross69822602014-08-12 15:51:37 -0700794 // Delete the Images before the TextureStorage.
795 // Images might be relying on the TextureStorage for some of their data.
796 // 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 -0700797 for (int i = 0; i < 6; i++)
798 {
799 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
800 {
801 SafeDelete(mImageArray[i][j]);
802 }
803 }
Austin Kinross69822602014-08-12 15:51:37 -0700804
805 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700806}
807
Brandon Jonescef06ff2014-08-05 13:27:48 -0700808Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700809{
810 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700811 ASSERT(layer < 6);
812 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700813}
814
Jamie Madillfeda4d22014-09-17 13:03:29 -0400815Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
816{
817 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
818 ASSERT(index.layerIndex < 6);
819 return mImageArray[index.layerIndex][index.mipIndex];
820}
821
Brandon Jonescef06ff2014-08-05 13:27:48 -0700822GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700823{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700824 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
825 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700826}
827
Brandon Jonescef06ff2014-08-05 13:27:48 -0700828GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700829{
830 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700831 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700832 else
833 return GL_NONE;
834}
835
Brandon Jonescef06ff2014-08-05 13:27:48 -0700836bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700837{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700838 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700839}
840
Brandon Jonescef06ff2014-08-05 13:27:48 -0700841void 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 -0700842{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700843 ASSERT(depth == 1);
844
845 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400846 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700847
848 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
849
850 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
851}
852
Brandon Jonescef06ff2014-08-05 13:27:48 -0700853void 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 -0700854{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700855 ASSERT(depth == 1);
856
Brandon Jones0511e802014-07-14 16:27:26 -0700857 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700858 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
859
Brandon Jones0511e802014-07-14 16:27:26 -0700860 redefineImage(faceIndex, level, format, width, height);
861
862 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
863}
864
Brandon Jonescef06ff2014-08-05 13:27:48 -0700865void 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 -0700866{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700867 ASSERT(depth == 1 && zoffset == 0);
868
869 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
870
Jamie Madillfeda4d22014-09-17 13:03:29 -0400871 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
872 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index))
Brandon Jones0511e802014-07-14 16:27:26 -0700873 {
874 commitRect(faceIndex, level, xoffset, yoffset, width, height);
875 }
876}
877
Brandon Jonescef06ff2014-08-05 13:27:48 -0700878void 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 -0700879{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700880 ASSERT(depth == 1 && zoffset == 0);
881
882 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
883
Brandon Jones0511e802014-07-14 16:27:26 -0700884 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
885 {
886 commitRect(faceIndex, level, xoffset, yoffset, width, height);
887 }
888}
889
890void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
891{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700892 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400893 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
894
Brandon Jones0511e802014-07-14 16:27:26 -0700895 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
896
897 if (!mImageArray[faceIndex][level]->isRenderableFormat())
898 {
899 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
900 mDirtyImages = true;
901 }
902 else
903 {
904 ensureRenderTarget();
905 mImageArray[faceIndex][level]->markClean();
906
907 ASSERT(width == height);
908
909 if (width > 0 && isValidFaceLevel(faceIndex, level))
910 {
911 gl::Rectangle sourceRect;
912 sourceRect.x = x;
913 sourceRect.width = width;
914 sourceRect.y = y;
915 sourceRect.height = height;
916
Jamie Madill856d9d42014-09-18 15:08:49 -0400917 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700918 }
919 }
920}
921
922void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
923{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700925
926 // We can only make our texture storage to a render target if the level we're copying *to* is complete
927 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
928 // rely on the "getBaseLevel*" methods reliably otherwise.
929 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
930
931 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
932 {
933 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
934 mDirtyImages = true;
935 }
936 else
937 {
938 ensureRenderTarget();
939
940 if (isValidFaceLevel(faceIndex, level))
941 {
942 updateStorageFaceLevel(faceIndex, level);
943
944 gl::Rectangle sourceRect;
945 sourceRect.x = x;
946 sourceRect.width = width;
947 sourceRect.y = y;
948 sourceRect.height = height;
949
Jamie Madill856d9d42014-09-18 15:08:49 -0400950 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
951 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700952 }
953 }
954}
955
Brandon Jonescef06ff2014-08-05 13:27:48 -0700956void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700957{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700958 ASSERT(width == height);
959 ASSERT(depth == 1);
960
Brandon Jones0511e802014-07-14 16:27:26 -0700961 for (int level = 0; level < levels; level++)
962 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700963 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700964 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
965 {
966 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
967 }
968 }
969
970 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
971 {
972 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
973 {
974 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
975 }
976 }
977
978 mImmutable = true;
979
Jamie Madillc4833262014-09-18 16:18:26 -0400980 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400981 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
982 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -0700983}
984
Brandon Jones0511e802014-07-14 16:27:26 -0700985// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
986bool TextureD3D_Cube::isCubeComplete() const
987{
988 int baseWidth = getBaseLevelWidth();
989 int baseHeight = getBaseLevelHeight();
990 GLenum baseFormat = getBaseLevelInternalFormat();
991
992 if (baseWidth <= 0 || baseWidth != baseHeight)
993 {
994 return false;
995 }
996
997 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
998 {
999 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1000
1001 if (faceBaseImage.getWidth() != baseWidth ||
1002 faceBaseImage.getHeight() != baseHeight ||
1003 faceBaseImage.getInternalFormat() != baseFormat )
1004 {
1005 return false;
1006 }
1007 }
1008
1009 return true;
1010}
1011
Brandon Jones6053a522014-07-25 16:22:09 -07001012void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1013{
1014 UNREACHABLE();
1015}
1016
1017void TextureD3D_Cube::releaseTexImage()
1018{
1019 UNREACHABLE();
1020}
1021
1022
Jamie Madill4aa79e12014-09-29 10:46:14 -04001023void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001024{
1025 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1026 int levelCount = mipLevels();
1027 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1028 {
1029 for (int level = 1; level < levelCount; level++)
1030 {
1031 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1032 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1033 }
1034 }
Brandon Jones0511e802014-07-14 16:27:26 -07001035}
1036
Jamie Madillac7579c2014-09-17 16:59:33 -04001037unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001038{
Jamie Madillc4833262014-09-18 16:18:26 -04001039 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001040}
1041
Jamie Madillac7579c2014-09-17 16:59:33 -04001042RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001043{
Jamie Madillac7579c2014-09-17 16:59:33 -04001044 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001045
1046 // ensure the underlying texture is created
1047 if (!ensureRenderTarget())
1048 {
1049 return NULL;
1050 }
1051
Jamie Madillac7579c2014-09-17 16:59:33 -04001052 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001053 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001054}
1055
Brandon Jones0511e802014-07-14 16:27:26 -07001056void TextureD3D_Cube::initializeStorage(bool renderTarget)
1057{
1058 // Only initialize the first time this texture is used as a render target or shader resource
1059 if (mTexStorage)
1060 {
1061 return;
1062 }
1063
1064 // do not attempt to create storage for nonexistant data
1065 if (!isFaceLevelComplete(0, 0))
1066 {
1067 return;
1068 }
1069
1070 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1071
1072 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1073 ASSERT(mTexStorage);
1074
1075 // flush image data to the storage
1076 updateStorage();
1077}
1078
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001079TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001080{
1081 GLsizei size = getBaseLevelWidth();
1082
1083 ASSERT(size > 0);
1084
1085 // use existing storage level count, when previously specified by TexStorage*D
1086 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1087
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001088 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001089}
1090
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001091void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001092{
1093 SafeDelete(mTexStorage);
1094 mTexStorage = newCompleteTexStorage;
1095
1096 if (mTexStorage && mTexStorage->isManaged())
1097 {
1098 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1099 {
1100 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1101 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001102 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001103 }
1104 }
1105 }
1106
1107 mDirtyImages = true;
1108}
1109
1110void TextureD3D_Cube::updateStorage()
1111{
1112 ASSERT(mTexStorage != NULL);
1113 GLint storageLevels = mTexStorage->getLevelCount();
1114 for (int face = 0; face < 6; face++)
1115 {
1116 for (int level = 0; level < storageLevels; level++)
1117 {
1118 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1119 {
1120 updateStorageFaceLevel(face, level);
1121 }
1122 }
1123 }
1124}
1125
1126bool TextureD3D_Cube::ensureRenderTarget()
1127{
1128 initializeStorage(true);
1129
1130 if (getBaseLevelWidth() > 0)
1131 {
1132 ASSERT(mTexStorage);
1133 if (!mTexStorage->isRenderTarget())
1134 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001135 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001136
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001137 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001138 {
1139 delete newRenderTargetStorage;
1140 return gl::error(GL_OUT_OF_MEMORY, false);
1141 }
1142
1143 setCompleteTexStorage(newRenderTargetStorage);
1144 }
1145 }
1146
1147 return (mTexStorage && mTexStorage->isRenderTarget());
1148}
1149
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001150TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001151{
1152 return mTexStorage;
1153}
1154
1155const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1156{
1157 // Note: if we are not cube-complete, there is no single base level image that can describe all
1158 // cube faces, so this method is only well-defined for a cube-complete base level.
1159 return mImageArray[0][0];
1160}
1161
Brandon Jones0511e802014-07-14 16:27:26 -07001162bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1163{
1164 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1165}
1166
Brandon Jones0511e802014-07-14 16:27:26 -07001167bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1168{
1169 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1170
1171 if (isImmutable())
1172 {
1173 return true;
1174 }
1175
1176 int baseSize = getBaseLevelWidth();
1177
1178 if (baseSize <= 0)
1179 {
1180 return false;
1181 }
1182
1183 // "isCubeComplete" checks for base level completeness and we must call that
1184 // to determine if any face at level 0 is complete. We omit that check here
1185 // to avoid re-checking cube-completeness for every face at level 0.
1186 if (level == 0)
1187 {
1188 return true;
1189 }
1190
1191 // Check that non-zero levels are consistent with the base level.
1192 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1193
1194 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1195 {
1196 return false;
1197 }
1198
1199 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1200 {
1201 return false;
1202 }
1203
1204 return true;
1205}
1206
1207void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1208{
1209 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1210 ImageD3D *image = mImageArray[faceIndex][level];
1211
1212 if (image->isDirty())
1213 {
1214 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1215 }
1216}
1217
1218void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1219{
1220 // If there currently is a corresponding storage texture image, it has these parameters
1221 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1222 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1223 const GLenum storageFormat = getBaseLevelInternalFormat();
1224
1225 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1226
1227 if (mTexStorage)
1228 {
1229 const int storageLevels = mTexStorage->getLevelCount();
1230
1231 if ((level >= storageLevels && storageLevels != 0) ||
1232 width != storageWidth ||
1233 height != storageHeight ||
1234 internalformat != storageFormat) // Discard mismatched storage
1235 {
1236 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1237 {
1238 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1239 {
1240 mImageArray[faceIndex][level]->markDirty();
1241 }
1242 }
1243
1244 SafeDelete(mTexStorage);
1245
1246 mDirtyImages = true;
1247 }
1248 }
1249}
1250
1251void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1252{
1253 if (isValidFaceLevel(faceIndex, level))
1254 {
1255 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001256 if (image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
Brandon Jones0511e802014-07-14 16:27:26 -07001257 image->markClean();
1258 }
1259}
1260
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001261gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1262{
1263 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1264}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001265
Jamie Madillcb83dc12014-09-29 10:46:12 -04001266gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1267{
1268 // The "layer" of the image index corresponds to the cube face
1269 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1270}
1271
Brandon Jones78b1acd2014-07-15 15:33:07 -07001272TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001273 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001274 mTexStorage(NULL)
1275{
1276 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1277 {
1278 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1279 }
1280}
1281
1282TextureD3D_3D::~TextureD3D_3D()
1283{
Austin Kinross69822602014-08-12 15:51:37 -07001284 // Delete the Images before the TextureStorage.
1285 // Images might be relying on the TextureStorage for some of their data.
1286 // 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 -07001287 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1288 {
1289 delete mImageArray[i];
1290 }
Austin Kinross69822602014-08-12 15:51:37 -07001291
1292 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001293}
1294
Brandon Jonescef06ff2014-08-05 13:27:48 -07001295Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001296{
1297 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001298 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001299 return mImageArray[level];
1300}
1301
Jamie Madillfeda4d22014-09-17 13:03:29 -04001302Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1303{
1304 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001305 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001306 ASSERT(index.type == GL_TEXTURE_3D);
1307 return mImageArray[index.mipIndex];
1308}
1309
Brandon Jonescef06ff2014-08-05 13:27:48 -07001310GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001311{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001312 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1313 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001314}
1315
Brandon Jones78b1acd2014-07-15 15:33:07 -07001316GLsizei TextureD3D_3D::getWidth(GLint level) const
1317{
1318 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1319 return mImageArray[level]->getWidth();
1320 else
1321 return 0;
1322}
1323
1324GLsizei TextureD3D_3D::getHeight(GLint level) const
1325{
1326 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1327 return mImageArray[level]->getHeight();
1328 else
1329 return 0;
1330}
1331
1332GLsizei TextureD3D_3D::getDepth(GLint level) const
1333{
1334 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1335 return mImageArray[level]->getDepth();
1336 else
1337 return 0;
1338}
1339
1340GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1341{
1342 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1343 return mImageArray[level]->getInternalFormat();
1344 else
1345 return GL_NONE;
1346}
1347
1348bool TextureD3D_3D::isDepth(GLint level) const
1349{
Geoff Lang5d601382014-07-22 15:14:06 -04001350 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001351}
1352
Brandon Jonescef06ff2014-08-05 13:27:48 -07001353void 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 -07001354{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001355 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001356 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1357
Brandon Jones78b1acd2014-07-15 15:33:07 -07001358 redefineImage(level, sizedInternalFormat, width, height, depth);
1359
1360 bool fastUnpacked = false;
1361
1362 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1363 if (isFastUnpackable(unpack, sizedInternalFormat))
1364 {
1365 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001366 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1367 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001368 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1369
1370 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1371 {
1372 // Ensure we don't overwrite our newly initialized data
1373 mImageArray[level]->markClean();
1374
1375 fastUnpacked = true;
1376 }
1377 }
1378
1379 if (!fastUnpacked)
1380 {
1381 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1382 }
1383}
1384
Brandon Jonescef06ff2014-08-05 13:27:48 -07001385void 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 -07001386{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001387 ASSERT(target == GL_TEXTURE_3D);
1388
Brandon Jones78b1acd2014-07-15 15:33:07 -07001389 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1390 redefineImage(level, format, width, height, depth);
1391
1392 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1393}
1394
Brandon Jonescef06ff2014-08-05 13:27:48 -07001395void 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 -07001396{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001397 ASSERT(target == GL_TEXTURE_3D);
1398
Brandon Jones78b1acd2014-07-15 15:33:07 -07001399 bool fastUnpacked = false;
1400
Jamie Madillac7579c2014-09-17 16:59:33 -04001401 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1402
Brandon Jones78b1acd2014-07-15 15:33:07 -07001403 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1404 if (isFastUnpackable(unpack, getInternalFormat(level)))
1405 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001406 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001407 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1408
1409 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1410 {
1411 // Ensure we don't overwrite our newly initialized data
1412 mImageArray[level]->markClean();
1413
1414 fastUnpacked = true;
1415 }
1416 }
1417
Jamie Madillfeda4d22014-09-17 13:03:29 -04001418 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001419 {
1420 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1421 }
1422}
1423
Brandon Jonescef06ff2014-08-05 13:27:48 -07001424void 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 -07001425{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001426 ASSERT(target == GL_TEXTURE_3D);
1427
Brandon Jones78b1acd2014-07-15 15:33:07 -07001428 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1429 {
1430 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1431 }
1432}
1433
Brandon Jonescef06ff2014-08-05 13:27:48 -07001434void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1435{
1436 UNIMPLEMENTED();
1437}
1438
Brandon Jones78b1acd2014-07-15 15:33:07 -07001439void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1440{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001441 ASSERT(target == GL_TEXTURE_3D);
1442
Brandon Jones78b1acd2014-07-15 15:33:07 -07001443 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1444 // the current level we're copying to is defined (with appropriate format, width & height)
1445 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1446
1447 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1448 {
1449 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1450 mDirtyImages = true;
1451 }
1452 else
1453 {
1454 ensureRenderTarget();
1455
1456 if (isValidLevel(level))
1457 {
1458 updateStorageLevel(level);
1459
1460 gl::Rectangle sourceRect;
1461 sourceRect.x = x;
1462 sourceRect.width = width;
1463 sourceRect.y = y;
1464 sourceRect.height = height;
1465
Jamie Madill856d9d42014-09-18 15:08:49 -04001466 mRenderer->copyImage3D(source, sourceRect,
1467 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1468 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001469 }
1470 }
1471}
1472
Brandon Jonescef06ff2014-08-05 13:27:48 -07001473void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001474{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001475 ASSERT(target == GL_TEXTURE_3D);
1476
Brandon Jones78b1acd2014-07-15 15:33:07 -07001477 for (int level = 0; level < levels; level++)
1478 {
1479 GLsizei levelWidth = std::max(1, width >> level);
1480 GLsizei levelHeight = std::max(1, height >> level);
1481 GLsizei levelDepth = std::max(1, depth >> level);
1482 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1483 }
1484
1485 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1486 {
1487 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1488 }
1489
1490 mImmutable = true;
1491
Jamie Madillc4833262014-09-18 16:18:26 -04001492 bool renderTarget = IsRenderTargetUsage(mUsage);
1493 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001494 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495}
1496
Brandon Jones6053a522014-07-25 16:22:09 -07001497void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001498{
Brandon Jones6053a522014-07-25 16:22:09 -07001499 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500}
1501
Brandon Jones6053a522014-07-25 16:22:09 -07001502void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503{
Brandon Jones6053a522014-07-25 16:22:09 -07001504 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001505}
1506
Brandon Jones6053a522014-07-25 16:22:09 -07001507
Jamie Madill4aa79e12014-09-29 10:46:14 -04001508void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001509{
1510 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1511 int levelCount = mipLevels();
1512 for (int level = 1; level < levelCount; level++)
1513 {
1514 redefineImage(level, getBaseLevelInternalFormat(),
1515 std::max(getBaseLevelWidth() >> level, 1),
1516 std::max(getBaseLevelHeight() >> level, 1),
1517 std::max(getBaseLevelDepth() >> level, 1));
1518 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001519}
1520
Jamie Madillac7579c2014-09-17 16:59:33 -04001521unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001522{
Jamie Madillc4833262014-09-18 16:18:26 -04001523 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001524}
1525
Jamie Madillac7579c2014-09-17 16:59:33 -04001526RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001527{
1528 // ensure the underlying texture is created
1529 if (!ensureRenderTarget())
1530 {
1531 return NULL;
1532 }
1533
Jamie Madillac7579c2014-09-17 16:59:33 -04001534 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001536 updateStorage();
1537 }
1538 else
1539 {
1540 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001541 }
1542
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001543 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001544}
1545
1546void TextureD3D_3D::initializeStorage(bool renderTarget)
1547{
1548 // Only initialize the first time this texture is used as a render target or shader resource
1549 if (mTexStorage)
1550 {
1551 return;
1552 }
1553
1554 // do not attempt to create storage for nonexistant data
1555 if (!isLevelComplete(0))
1556 {
1557 return;
1558 }
1559
1560 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1561
1562 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1563 ASSERT(mTexStorage);
1564
1565 // flush image data to the storage
1566 updateStorage();
1567}
1568
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001569TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001570{
1571 GLsizei width = getBaseLevelWidth();
1572 GLsizei height = getBaseLevelHeight();
1573 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001574 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001575
1576 ASSERT(width > 0 && height > 0 && depth > 0);
1577
1578 // use existing storage level count, when previously specified by TexStorage*D
1579 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1580
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001581 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001582}
1583
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001584void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001585{
1586 SafeDelete(mTexStorage);
1587 mTexStorage = newCompleteTexStorage;
1588 mDirtyImages = true;
1589
1590 // We do not support managed 3D storage, as that is D3D9/ES2-only
1591 ASSERT(!mTexStorage->isManaged());
1592}
1593
1594void TextureD3D_3D::updateStorage()
1595{
1596 ASSERT(mTexStorage != NULL);
1597 GLint storageLevels = mTexStorage->getLevelCount();
1598 for (int level = 0; level < storageLevels; level++)
1599 {
1600 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1601 {
1602 updateStorageLevel(level);
1603 }
1604 }
1605}
1606
1607bool TextureD3D_3D::ensureRenderTarget()
1608{
1609 initializeStorage(true);
1610
1611 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1612 {
1613 ASSERT(mTexStorage);
1614 if (!mTexStorage->isRenderTarget())
1615 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001616 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001617
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001618 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001619 {
1620 delete newRenderTargetStorage;
1621 return gl::error(GL_OUT_OF_MEMORY, false);
1622 }
1623
1624 setCompleteTexStorage(newRenderTargetStorage);
1625 }
1626 }
1627
1628 return (mTexStorage && mTexStorage->isRenderTarget());
1629}
1630
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001631TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001632{
1633 return mTexStorage;
1634}
1635
1636const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1637{
1638 return mImageArray[0];
1639}
1640
1641bool TextureD3D_3D::isValidLevel(int level) const
1642{
1643 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1644}
1645
1646bool TextureD3D_3D::isLevelComplete(int level) const
1647{
1648 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1649
1650 if (isImmutable())
1651 {
1652 return true;
1653 }
1654
1655 GLsizei width = getBaseLevelWidth();
1656 GLsizei height = getBaseLevelHeight();
1657 GLsizei depth = getBaseLevelDepth();
1658
1659 if (width <= 0 || height <= 0 || depth <= 0)
1660 {
1661 return false;
1662 }
1663
1664 if (level == 0)
1665 {
1666 return true;
1667 }
1668
1669 ImageD3D *levelImage = mImageArray[level];
1670
1671 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1672 {
1673 return false;
1674 }
1675
1676 if (levelImage->getWidth() != std::max(1, width >> level))
1677 {
1678 return false;
1679 }
1680
1681 if (levelImage->getHeight() != std::max(1, height >> level))
1682 {
1683 return false;
1684 }
1685
1686 if (levelImage->getDepth() != std::max(1, depth >> level))
1687 {
1688 return false;
1689 }
1690
1691 return true;
1692}
1693
1694void TextureD3D_3D::updateStorageLevel(int level)
1695{
1696 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1697 ASSERT(isLevelComplete(level));
1698
1699 if (mImageArray[level]->isDirty())
1700 {
1701 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1702 }
1703}
1704
1705void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1706{
1707 // If there currently is a corresponding storage texture image, it has these parameters
1708 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1709 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1710 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1711 const GLenum storageFormat = getBaseLevelInternalFormat();
1712
1713 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1714
1715 if (mTexStorage)
1716 {
1717 const int storageLevels = mTexStorage->getLevelCount();
1718
1719 if ((level >= storageLevels && storageLevels != 0) ||
1720 width != storageWidth ||
1721 height != storageHeight ||
1722 depth != storageDepth ||
1723 internalformat != storageFormat) // Discard mismatched storage
1724 {
1725 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1726 {
1727 mImageArray[i]->markDirty();
1728 }
1729
1730 SafeDelete(mTexStorage);
1731 mDirtyImages = true;
1732 }
1733 }
1734}
1735
1736void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1737{
1738 if (isValidLevel(level))
1739 {
1740 ImageD3D *image = mImageArray[level];
Jamie Madill856d9d42014-09-18 15:08:49 -04001741 if (image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001742 {
1743 image->markClean();
1744 }
1745 }
1746}
1747
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001748gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1749{
1750 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1751 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1752}
Brandon Jones142ec422014-07-16 10:31:30 -07001753
Jamie Madillcb83dc12014-09-29 10:46:12 -04001754gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1755{
1756 // The "layer" here does not apply to 3D images. We use one Image per mip.
1757 return gl::ImageIndex::Make3D(mip);
1758}
1759
Brandon Jones142ec422014-07-16 10:31:30 -07001760TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001761 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001762 mTexStorage(NULL)
1763{
1764 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1765 {
1766 mLayerCounts[level] = 0;
1767 mImageArray[level] = NULL;
1768 }
1769}
1770
1771TextureD3D_2DArray::~TextureD3D_2DArray()
1772{
Austin Kinross69822602014-08-12 15:51:37 -07001773 // Delete the Images before the TextureStorage.
1774 // Images might be relying on the TextureStorage for some of their data.
1775 // 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 -07001776 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001777 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001778}
1779
Brandon Jones142ec422014-07-16 10:31:30 -07001780Image *TextureD3D_2DArray::getImage(int level, int layer) const
1781{
1782 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1783 ASSERT(layer < mLayerCounts[level]);
1784 return mImageArray[level][layer];
1785}
1786
Jamie Madillfeda4d22014-09-17 13:03:29 -04001787Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1788{
1789 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1790 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1791 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1792 return mImageArray[index.mipIndex][index.layerIndex];
1793}
1794
Brandon Jones142ec422014-07-16 10:31:30 -07001795GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1796{
1797 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1798 return mLayerCounts[level];
1799}
1800
Brandon Jones142ec422014-07-16 10:31:30 -07001801GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1802{
1803 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1804}
1805
1806GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1807{
1808 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1809}
1810
1811GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1812{
1813 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1814}
1815
1816GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1817{
1818 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1819}
1820
1821bool TextureD3D_2DArray::isDepth(GLint level) const
1822{
Geoff Lang5d601382014-07-22 15:14:06 -04001823 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001824}
1825
Brandon Jonescef06ff2014-08-05 13:27:48 -07001826void 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 -07001827{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001828 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1829
Geoff Lang5d601382014-07-22 15:14:06 -04001830 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1831
Brandon Jones142ec422014-07-16 10:31:30 -07001832 redefineImage(level, sizedInternalFormat, width, height, depth);
1833
Geoff Lang5d601382014-07-22 15:14:06 -04001834 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1835 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001836
1837 for (int i = 0; i < depth; i++)
1838 {
1839 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1840 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1841 }
1842}
1843
Brandon Jonescef06ff2014-08-05 13:27:48 -07001844void 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 -07001845{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001846 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1847
Brandon Jones142ec422014-07-16 10:31:30 -07001848 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1849 redefineImage(level, format, width, height, depth);
1850
Geoff Lang5d601382014-07-22 15:14:06 -04001851 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1852 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001853
1854 for (int i = 0; i < depth; i++)
1855 {
1856 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1857 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1858 }
1859}
1860
Brandon Jonescef06ff2014-08-05 13:27:48 -07001861void 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 -07001862{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001863 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1864
Geoff Lang5d601382014-07-22 15:14:06 -04001865 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1866 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001867
1868 for (int i = 0; i < depth; i++)
1869 {
1870 int layer = zoffset + i;
1871 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1872
Jamie Madillfeda4d22014-09-17 13:03:29 -04001873 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1874 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, index))
Brandon Jones142ec422014-07-16 10:31:30 -07001875 {
1876 commitRect(level, xoffset, yoffset, layer, width, height);
1877 }
1878 }
1879}
1880
Brandon Jonescef06ff2014-08-05 13:27:48 -07001881void 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 -07001882{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001883 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1884
Geoff Lang5d601382014-07-22 15:14:06 -04001885 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1886 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001887
1888 for (int i = 0; i < depth; i++)
1889 {
1890 int layer = zoffset + i;
1891 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1892
1893 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1894 {
1895 commitRect(level, xoffset, yoffset, layer, width, height);
1896 }
1897 }
1898}
1899
Brandon Jonescef06ff2014-08-05 13:27:48 -07001900void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1901{
1902 UNIMPLEMENTED();
1903}
1904
Brandon Jones142ec422014-07-16 10:31:30 -07001905void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1906{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001907 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1908
Brandon Jones142ec422014-07-16 10:31:30 -07001909 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1910 // the current level we're copying to is defined (with appropriate format, width & height)
1911 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1912
1913 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1914 {
1915 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1916 mDirtyImages = true;
1917 }
1918 else
1919 {
1920 ensureRenderTarget();
1921
1922 if (isValidLevel(level))
1923 {
1924 updateStorageLevel(level);
1925
1926 gl::Rectangle sourceRect;
1927 sourceRect.x = x;
1928 sourceRect.width = width;
1929 sourceRect.y = y;
1930 sourceRect.height = height;
1931
Jamie Madill856d9d42014-09-18 15:08:49 -04001932 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
1933 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07001934 }
1935 }
1936}
1937
Brandon Jonescef06ff2014-08-05 13:27:48 -07001938void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001939{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001940 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1941
Brandon Jones142ec422014-07-16 10:31:30 -07001942 deleteImages();
1943
1944 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1945 {
1946 GLsizei levelWidth = std::max(1, width >> level);
1947 GLsizei levelHeight = std::max(1, height >> level);
1948
1949 mLayerCounts[level] = (level < levels ? depth : 0);
1950
1951 if (mLayerCounts[level] > 0)
1952 {
1953 // Create new images for this level
1954 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1955
1956 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1957 {
1958 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1959 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1960 levelHeight, 1, true);
1961 }
1962 }
1963 }
1964
1965 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04001966
1967 bool renderTarget = IsRenderTargetUsage(mUsage);
1968 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001969 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07001970}
1971
Brandon Jones6053a522014-07-25 16:22:09 -07001972void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001973{
Brandon Jones6053a522014-07-25 16:22:09 -07001974 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001975}
1976
Brandon Jones6053a522014-07-25 16:22:09 -07001977void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001978{
Brandon Jones6053a522014-07-25 16:22:09 -07001979 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001980}
1981
Brandon Jones6053a522014-07-25 16:22:09 -07001982
Jamie Madill4aa79e12014-09-29 10:46:14 -04001983void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07001984{
1985 int baseWidth = getBaseLevelWidth();
1986 int baseHeight = getBaseLevelHeight();
1987 int baseDepth = getBaseLevelDepth();
1988 GLenum baseFormat = getBaseLevelInternalFormat();
1989
1990 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1991 int levelCount = mipLevels();
1992 for (int level = 1; level < levelCount; level++)
1993 {
1994 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
1995 }
Brandon Jones142ec422014-07-16 10:31:30 -07001996}
1997
Jamie Madillac7579c2014-09-17 16:59:33 -04001998unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07001999{
Jamie Madillc4833262014-09-18 16:18:26 -04002000 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002001}
2002
Jamie Madillac7579c2014-09-17 16:59:33 -04002003RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002004{
2005 // ensure the underlying texture is created
2006 if (!ensureRenderTarget())
2007 {
2008 return NULL;
2009 }
2010
Jamie Madillac7579c2014-09-17 16:59:33 -04002011 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002012 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002013}
2014
2015void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2016{
2017 // Only initialize the first time this texture is used as a render target or shader resource
2018 if (mTexStorage)
2019 {
2020 return;
2021 }
2022
2023 // do not attempt to create storage for nonexistant data
2024 if (!isLevelComplete(0))
2025 {
2026 return;
2027 }
2028
2029 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2030
2031 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2032 ASSERT(mTexStorage);
2033
2034 // flush image data to the storage
2035 updateStorage();
2036}
2037
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002038TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002039{
2040 GLsizei width = getBaseLevelWidth();
2041 GLsizei height = getBaseLevelHeight();
2042 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002043 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002044
2045 ASSERT(width > 0 && height > 0 && depth > 0);
2046
2047 // use existing storage level count, when previously specified by TexStorage*D
2048 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2049
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002050 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002051}
2052
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002053void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002054{
2055 SafeDelete(mTexStorage);
2056 mTexStorage = newCompleteTexStorage;
2057 mDirtyImages = true;
2058
2059 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2060 ASSERT(!mTexStorage->isManaged());
2061}
2062
2063void TextureD3D_2DArray::updateStorage()
2064{
2065 ASSERT(mTexStorage != NULL);
2066 GLint storageLevels = mTexStorage->getLevelCount();
2067 for (int level = 0; level < storageLevels; level++)
2068 {
2069 if (isLevelComplete(level))
2070 {
2071 updateStorageLevel(level);
2072 }
2073 }
2074}
2075
2076bool TextureD3D_2DArray::ensureRenderTarget()
2077{
2078 initializeStorage(true);
2079
2080 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2081 {
2082 ASSERT(mTexStorage);
2083 if (!mTexStorage->isRenderTarget())
2084 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002085 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002086
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002087 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002088 {
2089 delete newRenderTargetStorage;
2090 return gl::error(GL_OUT_OF_MEMORY, false);
2091 }
2092
2093 setCompleteTexStorage(newRenderTargetStorage);
2094 }
2095 }
2096
2097 return (mTexStorage && mTexStorage->isRenderTarget());
2098}
2099
2100const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2101{
2102 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2103}
2104
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002105TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002106{
2107 return mTexStorage;
2108}
2109
2110bool TextureD3D_2DArray::isValidLevel(int level) const
2111{
2112 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2113}
2114
2115bool TextureD3D_2DArray::isLevelComplete(int level) const
2116{
2117 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2118
2119 if (isImmutable())
2120 {
2121 return true;
2122 }
2123
2124 GLsizei width = getBaseLevelWidth();
2125 GLsizei height = getBaseLevelHeight();
2126 GLsizei layers = getLayers(0);
2127
2128 if (width <= 0 || height <= 0 || layers <= 0)
2129 {
2130 return false;
2131 }
2132
2133 if (level == 0)
2134 {
2135 return true;
2136 }
2137
2138 if (getInternalFormat(level) != getInternalFormat(0))
2139 {
2140 return false;
2141 }
2142
2143 if (getWidth(level) != std::max(1, width >> level))
2144 {
2145 return false;
2146 }
2147
2148 if (getHeight(level) != std::max(1, height >> level))
2149 {
2150 return false;
2151 }
2152
2153 if (getLayers(level) != layers)
2154 {
2155 return false;
2156 }
2157
2158 return true;
2159}
2160
2161void TextureD3D_2DArray::updateStorageLevel(int level)
2162{
2163 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2164 ASSERT(isLevelComplete(level));
2165
2166 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2167 {
2168 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2169 if (mImageArray[level][layer]->isDirty())
2170 {
2171 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2172 }
2173 }
2174}
2175
2176void TextureD3D_2DArray::deleteImages()
2177{
2178 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2179 {
2180 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2181 {
2182 delete mImageArray[level][layer];
2183 }
2184 delete[] mImageArray[level];
2185 mImageArray[level] = NULL;
2186 mLayerCounts[level] = 0;
2187 }
2188}
2189
2190void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2191{
2192 // If there currently is a corresponding storage texture image, it has these parameters
2193 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2194 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2195 const int storageDepth = getLayers(0);
2196 const GLenum storageFormat = getBaseLevelInternalFormat();
2197
2198 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2199 {
2200 delete mImageArray[level][layer];
2201 }
2202 delete[] mImageArray[level];
2203 mImageArray[level] = NULL;
2204 mLayerCounts[level] = depth;
2205
2206 if (depth > 0)
2207 {
2208 mImageArray[level] = new ImageD3D*[depth]();
2209
2210 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2211 {
2212 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2213 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2214 }
2215 }
2216
2217 if (mTexStorage)
2218 {
2219 const int storageLevels = mTexStorage->getLevelCount();
2220
2221 if ((level >= storageLevels && storageLevels != 0) ||
2222 width != storageWidth ||
2223 height != storageHeight ||
2224 depth != storageDepth ||
2225 internalformat != storageFormat) // Discard mismatched storage
2226 {
2227 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2228 {
2229 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2230 {
2231 mImageArray[level][layer]->markDirty();
2232 }
2233 }
2234
2235 delete mTexStorage;
2236 mTexStorage = NULL;
2237 mDirtyImages = true;
2238 }
2239 }
2240}
2241
2242void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2243{
2244 if (isValidLevel(level) && layerTarget < getLayers(level))
2245 {
2246 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill856d9d42014-09-18 15:08:49 -04002247 if (image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
Brandon Jones142ec422014-07-16 10:31:30 -07002248 {
2249 image->markClean();
2250 }
2251 }
2252}
2253
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002254gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2255{
2256 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2257}
2258
Jamie Madillcb83dc12014-09-29 10:46:12 -04002259gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2260{
2261 return gl::ImageIndex::Make2DArray(mip, layer);
2262}
2263
Brandon Jones78b1acd2014-07-15 15:33:07 -07002264}