blob: fc1ebeff73456b367222b7c6b9a93c6f94f419a1 [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
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040093gl::Error 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 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040098 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -070099 }
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 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400118 gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 if (error.isError())
120 {
121 return error;
122 }
123
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 mDirtyImages = true;
125 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400126
127 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700128}
129
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400130gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
131 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700132{
133 const void *pixelData = pixels;
134
135 // CPU readback & copy where direct GPU copy is not supported
136 if (unpack.pixelBuffer.id() != 0)
137 {
138 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
139 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
140 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
141 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
142 const void *bufferData = pixelBuffer->getImplementation()->getData();
143 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
144 }
145
146 if (pixelData != NULL)
147 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400148 Image *image = getImage(index);
149 ASSERT(image);
150
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400151 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
152 type, pixelData);
153 if (error.isError())
154 {
155 return error;
156 }
157
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158 mDirtyImages = true;
159 }
160
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400161 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162}
163
Brandon Jones78b1acd2014-07-15 15:33:07 -0700164void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165{
166 if (pixels != NULL)
167 {
168 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
169 mDirtyImages = true;
170 }
171}
172
173bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700174 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700175{
176 if (pixels != NULL)
177 {
178 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
179 mDirtyImages = true;
180 }
181
182 return true;
183}
184
185bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
186{
187 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
188}
189
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400190gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
191 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700192{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400193 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
195 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400196 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700197 }
198
199 // In order to perform the fast copy through the shader, we must have the right format, and be able
200 // to create a render target.
201 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
202
203 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
204
Geoff Langae5122c2014-08-27 14:08:43 -0400205 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
206 if (error.isError())
207 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400208 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400209 }
210
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400211 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700212}
213
214GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
215{
216 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
217 {
218 // Maximum number of levels
219 return gl::log2(std::max(std::max(width, height), depth)) + 1;
220 }
221 else
222 {
223 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
224 return 1;
225 }
226}
227
228int TextureD3D::mipLevels() const
229{
230 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
231}
232
Jamie Madill4aa79e12014-09-29 10:46:14 -0400233void TextureD3D::generateMipmaps()
234{
235 // Set up proper image sizes.
236 initMipmapsImages();
237
238 // We know that all layers have the same dimension, for the texture to be complete
239 GLint layerCount = static_cast<GLint>(getLayerCount(0));
240 GLint mipCount = mipLevels();
241
242 // The following will create and initialize the storage, or update it if it exists
243 TextureStorage *storage = getNativeTexture();
244
245 bool renderableStorage = (storage && storage->isRenderTarget());
246
247 for (GLint layer = 0; layer < layerCount; ++layer)
248 {
249 for (GLint mip = 1; mip < mipCount; ++mip)
250 {
251 ASSERT(getLayerCount(mip) == layerCount);
252
253 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
254 gl::ImageIndex destIndex = getImageIndex(mip, layer);
255
256 if (renderableStorage)
257 {
258 // GPU-side mipmapping
259 storage->generateMipmap(sourceIndex, destIndex);
260 }
261 else
262 {
263 // CPU-side mipmapping
264 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
265 }
266 }
267 }
268}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700269
Brandon Jones78b1acd2014-07-15 15:33:07 -0700270TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700271 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700272 mTexStorage(NULL)
273{
274 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
275 {
276 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
277 }
278}
279
280TextureD3D_2D::~TextureD3D_2D()
281{
Austin Kinross69822602014-08-12 15:51:37 -0700282 // Delete the Images before the TextureStorage.
283 // Images might be relying on the TextureStorage for some of their data.
284 // 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 -0700285 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
286 {
287 delete mImageArray[i];
288 }
Austin Kinross69822602014-08-12 15:51:37 -0700289
290 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700291}
292
Brandon Jonescef06ff2014-08-05 13:27:48 -0700293Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294{
295 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700296 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700297 return mImageArray[level];
298}
299
Jamie Madillfeda4d22014-09-17 13:03:29 -0400300Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
301{
302 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400303 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400304 ASSERT(index.type == GL_TEXTURE_2D);
305 return mImageArray[index.mipIndex];
306}
307
Brandon Jonescef06ff2014-08-05 13:27:48 -0700308GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700309{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700310 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
311 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700312}
313
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700314GLsizei TextureD3D_2D::getWidth(GLint level) const
315{
316 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
317 return mImageArray[level]->getWidth();
318 else
319 return 0;
320}
321
322GLsizei TextureD3D_2D::getHeight(GLint level) const
323{
324 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
325 return mImageArray[level]->getHeight();
326 else
327 return 0;
328}
329
330GLenum TextureD3D_2D::getInternalFormat(GLint level) const
331{
332 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
333 return mImageArray[level]->getInternalFormat();
334 else
335 return GL_NONE;
336}
337
338GLenum TextureD3D_2D::getActualFormat(GLint level) const
339{
340 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
341 return mImageArray[level]->getActualFormat();
342 else
343 return GL_NONE;
344}
345
346bool TextureD3D_2D::isDepth(GLint level) const
347{
Geoff Lang5d601382014-07-22 15:14:06 -0400348 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700349}
350
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400351gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
352 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
353 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700354{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700355 ASSERT(target == GL_TEXTURE_2D && depth == 1);
356
Geoff Lang5d601382014-07-22 15:14:06 -0400357 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
358
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700359 bool fastUnpacked = false;
360
Brandon Jonescef06ff2014-08-05 13:27:48 -0700361 redefineImage(level, sizedInternalFormat, width, height);
362
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700363 // Attempt a fast gpu copy of the pixel data to the surface
364 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
365 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400366 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
367
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700368 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400369 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
371
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400372 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700373 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400374 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
375 if (error.isError())
376 {
377 return error;
378 }
379
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700380 // Ensure we don't overwrite our newly initialized data
381 mImageArray[level]->markClean();
382
383 fastUnpacked = true;
384 }
385 }
386
387 if (!fastUnpacked)
388 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400389 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
390 if (error.isError())
391 {
392 return error;
393 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700394 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400395
396 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700397}
398
Brandon Jonescef06ff2014-08-05 13:27:48 -0700399void 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 -0700400{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700401 ASSERT(target == GL_TEXTURE_2D && depth == 1);
402
403 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
404 redefineImage(level, format, width, height);
405
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700406 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
407}
408
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400409gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
410 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
411 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700412{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700413 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
414
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700415 bool fastUnpacked = false;
416
Jamie Madillac7579c2014-09-17 16:59:33 -0400417 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700418 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
419 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400420 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
422
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400423 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700424 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400425 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
426 if (error.isError())
427 {
428 return error;
429 }
430
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700431 // Ensure we don't overwrite our newly initialized data
432 mImageArray[level]->markClean();
433
434 fastUnpacked = true;
435 }
436 }
437
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400438 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700439 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400440 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
441 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
442 pixels, index);
443 if (error.isError())
444 {
445 return error;
446 }
447
448 error = commitRect(level, xoffset, yoffset, width, height);
449 if (error.isError())
450 {
451 return error;
452 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700453 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400454
455 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700456}
457
Brandon Jonescef06ff2014-08-05 13:27:48 -0700458void 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 -0700459{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700460 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
461
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700462 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
463 {
464 commitRect(level, xoffset, yoffset, width, height);
465 }
466}
467
Brandon Jonescef06ff2014-08-05 13:27:48 -0700468void 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 -0700469{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700470 ASSERT(target == GL_TEXTURE_2D);
471
472 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
473 redefineImage(level, sizedInternalFormat, width, height);
474
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700475 if (!mImageArray[level]->isRenderableFormat())
476 {
477 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
478 mDirtyImages = true;
479 }
480 else
481 {
482 ensureRenderTarget();
483 mImageArray[level]->markClean();
484
485 if (width != 0 && height != 0 && isValidLevel(level))
486 {
487 gl::Rectangle sourceRect;
488 sourceRect.x = x;
489 sourceRect.width = width;
490 sourceRect.y = y;
491 sourceRect.height = height;
492
Jamie Madill856d9d42014-09-18 15:08:49 -0400493 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700494 }
495 }
496}
497
498void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
499{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700500 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
501
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700502 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
503 // the current level we're copying to is defined (with appropriate format, width & height)
504 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
505
506 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
507 {
508 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
509 mDirtyImages = true;
510 }
511 else
512 {
513 ensureRenderTarget();
514
515 if (isValidLevel(level))
516 {
517 updateStorageLevel(level);
518
519 gl::Rectangle sourceRect;
520 sourceRect.x = x;
521 sourceRect.width = width;
522 sourceRect.y = y;
523 sourceRect.height = height;
524
Jamie Madill856d9d42014-09-18 15:08:49 -0400525 mRenderer->copyImage2D(source, sourceRect,
526 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
527 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528 }
529 }
530}
531
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700533{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700534 ASSERT(target == GL_TEXTURE_2D && depth == 1);
535
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536 for (int level = 0; level < levels; level++)
537 {
538 GLsizei levelWidth = std::max(1, width >> level);
539 GLsizei levelHeight = std::max(1, height >> level);
540 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
541 }
542
543 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
544 {
545 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
546 }
547
548 mImmutable = true;
549
Jamie Madillc4833262014-09-18 16:18:26 -0400550 bool renderTarget = IsRenderTargetUsage(mUsage);
551 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400552 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700553}
554
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555void TextureD3D_2D::bindTexImage(egl::Surface *surface)
556{
557 GLenum internalformat = surface->getFormat();
558
559 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
560
561 if (mTexStorage)
562 {
563 SafeDelete(mTexStorage);
564 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400565
566 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567
568 mDirtyImages = true;
569}
570
571void TextureD3D_2D::releaseTexImage()
572{
573 if (mTexStorage)
574 {
575 SafeDelete(mTexStorage);
576 }
577
578 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
579 {
580 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
581 }
582}
583
Jamie Madill4aa79e12014-09-29 10:46:14 -0400584void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700585{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700586 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700588 for (int level = 1; level < levelCount; level++)
589 {
590 redefineImage(level, getBaseLevelInternalFormat(),
591 std::max(getBaseLevelWidth() >> level, 1),
592 std::max(getBaseLevelHeight() >> level, 1));
593 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700594}
595
Jamie Madillac7579c2014-09-17 16:59:33 -0400596unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700597{
Jamie Madillac7579c2014-09-17 16:59:33 -0400598 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400599 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700600}
601
Jamie Madillac7579c2014-09-17 16:59:33 -0400602RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700603{
Jamie Madillac7579c2014-09-17 16:59:33 -0400604 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700605
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606 // ensure the underlying texture is created
607 if (!ensureRenderTarget())
608 {
609 return NULL;
610 }
611
Jamie Madillac7579c2014-09-17 16:59:33 -0400612 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400613 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614}
615
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616bool TextureD3D_2D::isValidLevel(int level) const
617{
618 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
619}
620
621bool TextureD3D_2D::isLevelComplete(int level) const
622{
623 if (isImmutable())
624 {
625 return true;
626 }
627
Brandon Jones78b1acd2014-07-15 15:33:07 -0700628 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700629
630 GLsizei width = baseImage->getWidth();
631 GLsizei height = baseImage->getHeight();
632
633 if (width <= 0 || height <= 0)
634 {
635 return false;
636 }
637
638 // The base image level is complete if the width and height are positive
639 if (level == 0)
640 {
641 return true;
642 }
643
644 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700645 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700646
647 if (image->getInternalFormat() != baseImage->getInternalFormat())
648 {
649 return false;
650 }
651
652 if (image->getWidth() != std::max(1, width >> level))
653 {
654 return false;
655 }
656
657 if (image->getHeight() != std::max(1, height >> level))
658 {
659 return false;
660 }
661
662 return true;
663}
664
665// Constructs a native texture resource from the texture images
666void TextureD3D_2D::initializeStorage(bool renderTarget)
667{
668 // Only initialize the first time this texture is used as a render target or shader resource
669 if (mTexStorage)
670 {
671 return;
672 }
673
674 // do not attempt to create storage for nonexistant data
675 if (!isLevelComplete(0))
676 {
677 return;
678 }
679
680 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
681
682 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
683 ASSERT(mTexStorage);
684
685 // flush image data to the storage
686 updateStorage();
687}
688
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400689TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700690{
691 GLsizei width = getBaseLevelWidth();
692 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400693 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694
695 ASSERT(width > 0 && height > 0);
696
697 // use existing storage level count, when previously specified by TexStorage*D
698 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
699
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400700 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700701}
702
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400703void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704{
705 SafeDelete(mTexStorage);
706 mTexStorage = newCompleteTexStorage;
707
708 if (mTexStorage && mTexStorage->isManaged())
709 {
710 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
711 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400712 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700713 }
714 }
715
716 mDirtyImages = true;
717}
718
719void TextureD3D_2D::updateStorage()
720{
721 ASSERT(mTexStorage != NULL);
722 GLint storageLevels = mTexStorage->getLevelCount();
723 for (int level = 0; level < storageLevels; level++)
724 {
725 if (mImageArray[level]->isDirty() && isLevelComplete(level))
726 {
727 updateStorageLevel(level);
728 }
729 }
730}
731
732bool TextureD3D_2D::ensureRenderTarget()
733{
734 initializeStorage(true);
735
736 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
737 {
738 ASSERT(mTexStorage);
739 if (!mTexStorage->isRenderTarget())
740 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400741 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742
Geoff Lang9e3f24f2014-08-27 12:06:04 -0400743 if (mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744 {
745 delete newRenderTargetStorage;
746 return gl::error(GL_OUT_OF_MEMORY, false);
747 }
748
749 setCompleteTexStorage(newRenderTargetStorage);
750 }
751 }
752
753 return (mTexStorage && mTexStorage->isRenderTarget());
754}
755
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400756TextureStorage *TextureD3D_2D::getBaseLevelStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700757{
758 return mTexStorage;
759}
760
761const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
762{
763 return mImageArray[0];
764}
765
766void TextureD3D_2D::updateStorageLevel(int level)
767{
768 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
769 ASSERT(isLevelComplete(level));
770
771 if (mImageArray[level]->isDirty())
772 {
773 commitRect(level, 0, 0, getWidth(level), getHeight(level));
774 }
775}
776
777void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
778{
779 // If there currently is a corresponding storage texture image, it has these parameters
780 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
781 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
782 const GLenum storageFormat = getBaseLevelInternalFormat();
783
784 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
785
786 if (mTexStorage)
787 {
788 const int storageLevels = mTexStorage->getLevelCount();
789
790 if ((level >= storageLevels && storageLevels != 0) ||
791 width != storageWidth ||
792 height != storageHeight ||
793 internalformat != storageFormat) // Discard mismatched storage
794 {
795 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
796 {
797 mImageArray[i]->markDirty();
798 }
799
800 SafeDelete(mTexStorage);
801 mDirtyImages = true;
802 }
803 }
804}
805
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400806gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700807{
808 if (isValidLevel(level))
809 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700810 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400811 gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
812 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400814 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700815 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400816
817 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400819
820 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700821}
822
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400823gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
824{
825 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
826}
Brandon Jones0511e802014-07-14 16:27:26 -0700827
Jamie Madillcb83dc12014-09-29 10:46:12 -0400828gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
829{
830 // "layer" does not apply to 2D Textures.
831 return gl::ImageIndex::Make2D(mip);
832}
833
Brandon Jones78b1acd2014-07-15 15:33:07 -0700834TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700835 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700836 mTexStorage(NULL)
837{
838 for (int i = 0; i < 6; i++)
839 {
840 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
841 {
842 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
843 }
844 }
845}
846
847TextureD3D_Cube::~TextureD3D_Cube()
848{
Austin Kinross69822602014-08-12 15:51:37 -0700849 // Delete the Images before the TextureStorage.
850 // Images might be relying on the TextureStorage for some of their data.
851 // 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 -0700852 for (int i = 0; i < 6; i++)
853 {
854 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
855 {
856 SafeDelete(mImageArray[i][j]);
857 }
858 }
Austin Kinross69822602014-08-12 15:51:37 -0700859
860 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700861}
862
Brandon Jonescef06ff2014-08-05 13:27:48 -0700863Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700864{
865 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700866 ASSERT(layer < 6);
867 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700868}
869
Jamie Madillfeda4d22014-09-17 13:03:29 -0400870Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
871{
872 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
873 ASSERT(index.layerIndex < 6);
874 return mImageArray[index.layerIndex][index.mipIndex];
875}
876
Brandon Jonescef06ff2014-08-05 13:27:48 -0700877GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700878{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700879 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
880 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700881}
882
Brandon Jonescef06ff2014-08-05 13:27:48 -0700883GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700884{
885 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700886 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700887 else
888 return GL_NONE;
889}
890
Brandon Jonescef06ff2014-08-05 13:27:48 -0700891bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700892{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700893 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700894}
895
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400896gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
897 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
898 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700899{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700900 ASSERT(depth == 1);
901
902 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400903 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700904
905 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
906
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400907 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700908}
909
Brandon Jonescef06ff2014-08-05 13:27:48 -0700910void 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 -0700911{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700912 ASSERT(depth == 1);
913
Brandon Jones0511e802014-07-14 16:27:26 -0700914 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700915 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
916
Brandon Jones0511e802014-07-14 16:27:26 -0700917 redefineImage(faceIndex, level, format, width, height);
918
919 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
920}
921
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400922gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
923 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
924 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700925{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700926 ASSERT(depth == 1 && zoffset == 0);
927
928 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
929
Jamie Madillfeda4d22014-09-17 13:03:29 -0400930 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400931 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
932 index);
933 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700934 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400935 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700936 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400937
938 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
939 if (error.isError())
940 {
941 return error;
942 }
943
944 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700945}
946
Brandon Jonescef06ff2014-08-05 13:27:48 -0700947void 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 -0700948{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700949 ASSERT(depth == 1 && zoffset == 0);
950
951 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
952
Brandon Jones0511e802014-07-14 16:27:26 -0700953 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
954 {
955 commitRect(faceIndex, level, xoffset, yoffset, width, height);
956 }
957}
958
959void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
960{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700961 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400962 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
963
Brandon Jones0511e802014-07-14 16:27:26 -0700964 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
965
966 if (!mImageArray[faceIndex][level]->isRenderableFormat())
967 {
968 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
969 mDirtyImages = true;
970 }
971 else
972 {
973 ensureRenderTarget();
974 mImageArray[faceIndex][level]->markClean();
975
976 ASSERT(width == height);
977
978 if (width > 0 && isValidFaceLevel(faceIndex, level))
979 {
980 gl::Rectangle sourceRect;
981 sourceRect.x = x;
982 sourceRect.width = width;
983 sourceRect.y = y;
984 sourceRect.height = height;
985
Jamie Madill856d9d42014-09-18 15:08:49 -0400986 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700987 }
988 }
989}
990
991void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
992{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700993 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700994
995 // We can only make our texture storage to a render target if the level we're copying *to* is complete
996 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
997 // rely on the "getBaseLevel*" methods reliably otherwise.
998 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
999
1000 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1001 {
1002 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1003 mDirtyImages = true;
1004 }
1005 else
1006 {
1007 ensureRenderTarget();
1008
1009 if (isValidFaceLevel(faceIndex, level))
1010 {
1011 updateStorageFaceLevel(faceIndex, level);
1012
1013 gl::Rectangle sourceRect;
1014 sourceRect.x = x;
1015 sourceRect.width = width;
1016 sourceRect.y = y;
1017 sourceRect.height = height;
1018
Jamie Madill856d9d42014-09-18 15:08:49 -04001019 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1020 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001021 }
1022 }
1023}
1024
Brandon Jonescef06ff2014-08-05 13:27:48 -07001025void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001026{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001027 ASSERT(width == height);
1028 ASSERT(depth == 1);
1029
Brandon Jones0511e802014-07-14 16:27:26 -07001030 for (int level = 0; level < levels; level++)
1031 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001032 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001033 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1034 {
1035 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1036 }
1037 }
1038
1039 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1040 {
1041 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1042 {
1043 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1044 }
1045 }
1046
1047 mImmutable = true;
1048
Jamie Madillc4833262014-09-18 16:18:26 -04001049 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001050 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1051 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001052}
1053
Brandon Jones0511e802014-07-14 16:27:26 -07001054// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1055bool TextureD3D_Cube::isCubeComplete() const
1056{
1057 int baseWidth = getBaseLevelWidth();
1058 int baseHeight = getBaseLevelHeight();
1059 GLenum baseFormat = getBaseLevelInternalFormat();
1060
1061 if (baseWidth <= 0 || baseWidth != baseHeight)
1062 {
1063 return false;
1064 }
1065
1066 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1067 {
1068 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1069
1070 if (faceBaseImage.getWidth() != baseWidth ||
1071 faceBaseImage.getHeight() != baseHeight ||
1072 faceBaseImage.getInternalFormat() != baseFormat )
1073 {
1074 return false;
1075 }
1076 }
1077
1078 return true;
1079}
1080
Brandon Jones6053a522014-07-25 16:22:09 -07001081void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1082{
1083 UNREACHABLE();
1084}
1085
1086void TextureD3D_Cube::releaseTexImage()
1087{
1088 UNREACHABLE();
1089}
1090
1091
Jamie Madill4aa79e12014-09-29 10:46:14 -04001092void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001093{
1094 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1095 int levelCount = mipLevels();
1096 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1097 {
1098 for (int level = 1; level < levelCount; level++)
1099 {
1100 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1101 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1102 }
1103 }
Brandon Jones0511e802014-07-14 16:27:26 -07001104}
1105
Jamie Madillac7579c2014-09-17 16:59:33 -04001106unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001107{
Jamie Madillc4833262014-09-18 16:18:26 -04001108 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001109}
1110
Jamie Madillac7579c2014-09-17 16:59:33 -04001111RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001112{
Jamie Madillac7579c2014-09-17 16:59:33 -04001113 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001114
1115 // ensure the underlying texture is created
1116 if (!ensureRenderTarget())
1117 {
1118 return NULL;
1119 }
1120
Jamie Madillac7579c2014-09-17 16:59:33 -04001121 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001122 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001123}
1124
Brandon Jones0511e802014-07-14 16:27:26 -07001125void TextureD3D_Cube::initializeStorage(bool renderTarget)
1126{
1127 // Only initialize the first time this texture is used as a render target or shader resource
1128 if (mTexStorage)
1129 {
1130 return;
1131 }
1132
1133 // do not attempt to create storage for nonexistant data
1134 if (!isFaceLevelComplete(0, 0))
1135 {
1136 return;
1137 }
1138
1139 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1140
1141 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1142 ASSERT(mTexStorage);
1143
1144 // flush image data to the storage
1145 updateStorage();
1146}
1147
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001148TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001149{
1150 GLsizei size = getBaseLevelWidth();
1151
1152 ASSERT(size > 0);
1153
1154 // use existing storage level count, when previously specified by TexStorage*D
1155 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1156
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001157 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001158}
1159
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001160void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001161{
1162 SafeDelete(mTexStorage);
1163 mTexStorage = newCompleteTexStorage;
1164
1165 if (mTexStorage && mTexStorage->isManaged())
1166 {
1167 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1168 {
1169 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1170 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001171 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001172 }
1173 }
1174 }
1175
1176 mDirtyImages = true;
1177}
1178
1179void TextureD3D_Cube::updateStorage()
1180{
1181 ASSERT(mTexStorage != NULL);
1182 GLint storageLevels = mTexStorage->getLevelCount();
1183 for (int face = 0; face < 6; face++)
1184 {
1185 for (int level = 0; level < storageLevels; level++)
1186 {
1187 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1188 {
1189 updateStorageFaceLevel(face, level);
1190 }
1191 }
1192 }
1193}
1194
1195bool TextureD3D_Cube::ensureRenderTarget()
1196{
1197 initializeStorage(true);
1198
1199 if (getBaseLevelWidth() > 0)
1200 {
1201 ASSERT(mTexStorage);
1202 if (!mTexStorage->isRenderTarget())
1203 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001204 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001205
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001206 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001207 {
1208 delete newRenderTargetStorage;
1209 return gl::error(GL_OUT_OF_MEMORY, false);
1210 }
1211
1212 setCompleteTexStorage(newRenderTargetStorage);
1213 }
1214 }
1215
1216 return (mTexStorage && mTexStorage->isRenderTarget());
1217}
1218
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001219TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001220{
1221 return mTexStorage;
1222}
1223
1224const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1225{
1226 // Note: if we are not cube-complete, there is no single base level image that can describe all
1227 // cube faces, so this method is only well-defined for a cube-complete base level.
1228 return mImageArray[0][0];
1229}
1230
Brandon Jones0511e802014-07-14 16:27:26 -07001231bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1232{
1233 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1234}
1235
Brandon Jones0511e802014-07-14 16:27:26 -07001236bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1237{
1238 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1239
1240 if (isImmutable())
1241 {
1242 return true;
1243 }
1244
1245 int baseSize = getBaseLevelWidth();
1246
1247 if (baseSize <= 0)
1248 {
1249 return false;
1250 }
1251
1252 // "isCubeComplete" checks for base level completeness and we must call that
1253 // to determine if any face at level 0 is complete. We omit that check here
1254 // to avoid re-checking cube-completeness for every face at level 0.
1255 if (level == 0)
1256 {
1257 return true;
1258 }
1259
1260 // Check that non-zero levels are consistent with the base level.
1261 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1262
1263 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1264 {
1265 return false;
1266 }
1267
1268 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1269 {
1270 return false;
1271 }
1272
1273 return true;
1274}
1275
1276void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1277{
1278 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1279 ImageD3D *image = mImageArray[faceIndex][level];
1280
1281 if (image->isDirty())
1282 {
1283 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1284 }
1285}
1286
1287void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1288{
1289 // If there currently is a corresponding storage texture image, it has these parameters
1290 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1291 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1292 const GLenum storageFormat = getBaseLevelInternalFormat();
1293
1294 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1295
1296 if (mTexStorage)
1297 {
1298 const int storageLevels = mTexStorage->getLevelCount();
1299
1300 if ((level >= storageLevels && storageLevels != 0) ||
1301 width != storageWidth ||
1302 height != storageHeight ||
1303 internalformat != storageFormat) // Discard mismatched storage
1304 {
1305 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1306 {
1307 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1308 {
1309 mImageArray[faceIndex][level]->markDirty();
1310 }
1311 }
1312
1313 SafeDelete(mTexStorage);
1314
1315 mDirtyImages = true;
1316 }
1317 }
1318}
1319
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001320gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jones0511e802014-07-14 16:27:26 -07001321{
1322 if (isValidFaceLevel(faceIndex, level))
1323 {
1324 ImageD3D *image = mImageArray[faceIndex][level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001325 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
1326 if (error.isError())
1327 {
1328 return error;
1329 }
1330
1331 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001332 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001333
1334 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001335}
1336
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001337gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1338{
1339 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1340}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001341
Jamie Madillcb83dc12014-09-29 10:46:12 -04001342gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1343{
1344 // The "layer" of the image index corresponds to the cube face
1345 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1346}
1347
Brandon Jones78b1acd2014-07-15 15:33:07 -07001348TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001349 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001350 mTexStorage(NULL)
1351{
1352 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1353 {
1354 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1355 }
1356}
1357
1358TextureD3D_3D::~TextureD3D_3D()
1359{
Austin Kinross69822602014-08-12 15:51:37 -07001360 // Delete the Images before the TextureStorage.
1361 // Images might be relying on the TextureStorage for some of their data.
1362 // 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 -07001363 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1364 {
1365 delete mImageArray[i];
1366 }
Austin Kinross69822602014-08-12 15:51:37 -07001367
1368 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001369}
1370
Brandon Jonescef06ff2014-08-05 13:27:48 -07001371Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001372{
1373 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001374 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001375 return mImageArray[level];
1376}
1377
Jamie Madillfeda4d22014-09-17 13:03:29 -04001378Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1379{
1380 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001381 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001382 ASSERT(index.type == GL_TEXTURE_3D);
1383 return mImageArray[index.mipIndex];
1384}
1385
Brandon Jonescef06ff2014-08-05 13:27:48 -07001386GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001387{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001388 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1389 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001390}
1391
Brandon Jones78b1acd2014-07-15 15:33:07 -07001392GLsizei TextureD3D_3D::getWidth(GLint level) const
1393{
1394 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1395 return mImageArray[level]->getWidth();
1396 else
1397 return 0;
1398}
1399
1400GLsizei TextureD3D_3D::getHeight(GLint level) const
1401{
1402 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1403 return mImageArray[level]->getHeight();
1404 else
1405 return 0;
1406}
1407
1408GLsizei TextureD3D_3D::getDepth(GLint level) const
1409{
1410 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1411 return mImageArray[level]->getDepth();
1412 else
1413 return 0;
1414}
1415
1416GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1417{
1418 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1419 return mImageArray[level]->getInternalFormat();
1420 else
1421 return GL_NONE;
1422}
1423
1424bool TextureD3D_3D::isDepth(GLint level) const
1425{
Geoff Lang5d601382014-07-22 15:14:06 -04001426 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001427}
1428
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001429gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1430 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1431 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001432{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001433 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001434 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1435
Brandon Jones78b1acd2014-07-15 15:33:07 -07001436 redefineImage(level, sizedInternalFormat, width, height, depth);
1437
1438 bool fastUnpacked = false;
1439
1440 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1441 if (isFastUnpackable(unpack, sizedInternalFormat))
1442 {
1443 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001444 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1445 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001446 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1447
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001448 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001449 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001450 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1451 if (error.isError())
1452 {
1453 return error;
1454 }
1455
Brandon Jones78b1acd2014-07-15 15:33:07 -07001456 // Ensure we don't overwrite our newly initialized data
1457 mImageArray[level]->markClean();
1458
1459 fastUnpacked = true;
1460 }
1461 }
1462
1463 if (!fastUnpacked)
1464 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001465 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1466 if (error.isError())
1467 {
1468 return error;
1469 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001470 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001471
1472 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001473}
1474
Brandon Jonescef06ff2014-08-05 13:27:48 -07001475void 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 -07001476{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001477 ASSERT(target == GL_TEXTURE_3D);
1478
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1480 redefineImage(level, format, width, height, depth);
1481
1482 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1483}
1484
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001485gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1486 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1487 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001488{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001489 ASSERT(target == GL_TEXTURE_3D);
1490
Brandon Jones78b1acd2014-07-15 15:33:07 -07001491 bool fastUnpacked = false;
1492
Jamie Madillac7579c2014-09-17 16:59:33 -04001493 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1494
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1496 if (isFastUnpackable(unpack, getInternalFormat(level)))
1497 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001498 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001499 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1500
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001501 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001502 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001503 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1504 if (error.isError())
1505 {
1506 return error;
1507 }
1508
Brandon Jones78b1acd2014-07-15 15:33:07 -07001509 // Ensure we don't overwrite our newly initialized data
1510 mImageArray[level]->markClean();
1511
1512 fastUnpacked = true;
1513 }
1514 }
1515
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001516 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001517 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001518 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1519 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1520 pixels, index);
1521 if (error.isError())
1522 {
1523 return error;
1524 }
1525
1526 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1527 if (error.isError())
1528 {
1529 return error;
1530 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001532
1533 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001534}
1535
Brandon Jonescef06ff2014-08-05 13:27:48 -07001536void 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 -07001537{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001538 ASSERT(target == GL_TEXTURE_3D);
1539
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1541 {
1542 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1543 }
1544}
1545
Brandon Jonescef06ff2014-08-05 13:27:48 -07001546void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1547{
1548 UNIMPLEMENTED();
1549}
1550
Brandon Jones78b1acd2014-07-15 15:33:07 -07001551void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1552{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001553 ASSERT(target == GL_TEXTURE_3D);
1554
Brandon Jones78b1acd2014-07-15 15:33:07 -07001555 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1556 // the current level we're copying to is defined (with appropriate format, width & height)
1557 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1558
1559 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1560 {
1561 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1562 mDirtyImages = true;
1563 }
1564 else
1565 {
1566 ensureRenderTarget();
1567
1568 if (isValidLevel(level))
1569 {
1570 updateStorageLevel(level);
1571
1572 gl::Rectangle sourceRect;
1573 sourceRect.x = x;
1574 sourceRect.width = width;
1575 sourceRect.y = y;
1576 sourceRect.height = height;
1577
Jamie Madill856d9d42014-09-18 15:08:49 -04001578 mRenderer->copyImage3D(source, sourceRect,
1579 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1580 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001581 }
1582 }
1583}
1584
Brandon Jonescef06ff2014-08-05 13:27:48 -07001585void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001586{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001587 ASSERT(target == GL_TEXTURE_3D);
1588
Brandon Jones78b1acd2014-07-15 15:33:07 -07001589 for (int level = 0; level < levels; level++)
1590 {
1591 GLsizei levelWidth = std::max(1, width >> level);
1592 GLsizei levelHeight = std::max(1, height >> level);
1593 GLsizei levelDepth = std::max(1, depth >> level);
1594 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1595 }
1596
1597 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1598 {
1599 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1600 }
1601
1602 mImmutable = true;
1603
Jamie Madillc4833262014-09-18 16:18:26 -04001604 bool renderTarget = IsRenderTargetUsage(mUsage);
1605 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001606 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001607}
1608
Brandon Jones6053a522014-07-25 16:22:09 -07001609void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001610{
Brandon Jones6053a522014-07-25 16:22:09 -07001611 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001612}
1613
Brandon Jones6053a522014-07-25 16:22:09 -07001614void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001615{
Brandon Jones6053a522014-07-25 16:22:09 -07001616 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001617}
1618
Brandon Jones6053a522014-07-25 16:22:09 -07001619
Jamie Madill4aa79e12014-09-29 10:46:14 -04001620void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001621{
1622 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1623 int levelCount = mipLevels();
1624 for (int level = 1; level < levelCount; level++)
1625 {
1626 redefineImage(level, getBaseLevelInternalFormat(),
1627 std::max(getBaseLevelWidth() >> level, 1),
1628 std::max(getBaseLevelHeight() >> level, 1),
1629 std::max(getBaseLevelDepth() >> level, 1));
1630 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001631}
1632
Jamie Madillac7579c2014-09-17 16:59:33 -04001633unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634{
Jamie Madillc4833262014-09-18 16:18:26 -04001635 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001636}
1637
Jamie Madillac7579c2014-09-17 16:59:33 -04001638RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639{
1640 // ensure the underlying texture is created
1641 if (!ensureRenderTarget())
1642 {
1643 return NULL;
1644 }
1645
Jamie Madillac7579c2014-09-17 16:59:33 -04001646 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001647 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001648 updateStorage();
1649 }
1650 else
1651 {
1652 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001653 }
1654
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001655 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656}
1657
1658void TextureD3D_3D::initializeStorage(bool renderTarget)
1659{
1660 // Only initialize the first time this texture is used as a render target or shader resource
1661 if (mTexStorage)
1662 {
1663 return;
1664 }
1665
1666 // do not attempt to create storage for nonexistant data
1667 if (!isLevelComplete(0))
1668 {
1669 return;
1670 }
1671
1672 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1673
1674 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1675 ASSERT(mTexStorage);
1676
1677 // flush image data to the storage
1678 updateStorage();
1679}
1680
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001681TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001682{
1683 GLsizei width = getBaseLevelWidth();
1684 GLsizei height = getBaseLevelHeight();
1685 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001686 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001687
1688 ASSERT(width > 0 && height > 0 && depth > 0);
1689
1690 // use existing storage level count, when previously specified by TexStorage*D
1691 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1692
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001693 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001694}
1695
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001696void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697{
1698 SafeDelete(mTexStorage);
1699 mTexStorage = newCompleteTexStorage;
1700 mDirtyImages = true;
1701
1702 // We do not support managed 3D storage, as that is D3D9/ES2-only
1703 ASSERT(!mTexStorage->isManaged());
1704}
1705
1706void TextureD3D_3D::updateStorage()
1707{
1708 ASSERT(mTexStorage != NULL);
1709 GLint storageLevels = mTexStorage->getLevelCount();
1710 for (int level = 0; level < storageLevels; level++)
1711 {
1712 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1713 {
1714 updateStorageLevel(level);
1715 }
1716 }
1717}
1718
1719bool TextureD3D_3D::ensureRenderTarget()
1720{
1721 initializeStorage(true);
1722
1723 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1724 {
1725 ASSERT(mTexStorage);
1726 if (!mTexStorage->isRenderTarget())
1727 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001728 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001729
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001730 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001731 {
1732 delete newRenderTargetStorage;
1733 return gl::error(GL_OUT_OF_MEMORY, false);
1734 }
1735
1736 setCompleteTexStorage(newRenderTargetStorage);
1737 }
1738 }
1739
1740 return (mTexStorage && mTexStorage->isRenderTarget());
1741}
1742
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001743TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001744{
1745 return mTexStorage;
1746}
1747
1748const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1749{
1750 return mImageArray[0];
1751}
1752
1753bool TextureD3D_3D::isValidLevel(int level) const
1754{
1755 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1756}
1757
1758bool TextureD3D_3D::isLevelComplete(int level) const
1759{
1760 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1761
1762 if (isImmutable())
1763 {
1764 return true;
1765 }
1766
1767 GLsizei width = getBaseLevelWidth();
1768 GLsizei height = getBaseLevelHeight();
1769 GLsizei depth = getBaseLevelDepth();
1770
1771 if (width <= 0 || height <= 0 || depth <= 0)
1772 {
1773 return false;
1774 }
1775
1776 if (level == 0)
1777 {
1778 return true;
1779 }
1780
1781 ImageD3D *levelImage = mImageArray[level];
1782
1783 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1784 {
1785 return false;
1786 }
1787
1788 if (levelImage->getWidth() != std::max(1, width >> level))
1789 {
1790 return false;
1791 }
1792
1793 if (levelImage->getHeight() != std::max(1, height >> level))
1794 {
1795 return false;
1796 }
1797
1798 if (levelImage->getDepth() != std::max(1, depth >> level))
1799 {
1800 return false;
1801 }
1802
1803 return true;
1804}
1805
1806void TextureD3D_3D::updateStorageLevel(int level)
1807{
1808 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1809 ASSERT(isLevelComplete(level));
1810
1811 if (mImageArray[level]->isDirty())
1812 {
1813 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1814 }
1815}
1816
1817void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1818{
1819 // If there currently is a corresponding storage texture image, it has these parameters
1820 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1821 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1822 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1823 const GLenum storageFormat = getBaseLevelInternalFormat();
1824
1825 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1826
1827 if (mTexStorage)
1828 {
1829 const int storageLevels = mTexStorage->getLevelCount();
1830
1831 if ((level >= storageLevels && storageLevels != 0) ||
1832 width != storageWidth ||
1833 height != storageHeight ||
1834 depth != storageDepth ||
1835 internalformat != storageFormat) // Discard mismatched storage
1836 {
1837 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1838 {
1839 mImageArray[i]->markDirty();
1840 }
1841
1842 SafeDelete(mTexStorage);
1843 mDirtyImages = true;
1844 }
1845 }
1846}
1847
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001848gl::Error TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849{
1850 if (isValidLevel(level))
1851 {
1852 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001853 gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
1854 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001856 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001857 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001858
1859 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001860 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001861
1862 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863}
1864
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001865gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1866{
1867 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1868 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1869}
Brandon Jones142ec422014-07-16 10:31:30 -07001870
Jamie Madillcb83dc12014-09-29 10:46:12 -04001871gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1872{
1873 // The "layer" here does not apply to 3D images. We use one Image per mip.
1874 return gl::ImageIndex::Make3D(mip);
1875}
1876
Brandon Jones142ec422014-07-16 10:31:30 -07001877TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001878 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001879 mTexStorage(NULL)
1880{
1881 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1882 {
1883 mLayerCounts[level] = 0;
1884 mImageArray[level] = NULL;
1885 }
1886}
1887
1888TextureD3D_2DArray::~TextureD3D_2DArray()
1889{
Austin Kinross69822602014-08-12 15:51:37 -07001890 // Delete the Images before the TextureStorage.
1891 // Images might be relying on the TextureStorage for some of their data.
1892 // 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 -07001893 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001894 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001895}
1896
Brandon Jones142ec422014-07-16 10:31:30 -07001897Image *TextureD3D_2DArray::getImage(int level, int layer) const
1898{
1899 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1900 ASSERT(layer < mLayerCounts[level]);
1901 return mImageArray[level][layer];
1902}
1903
Jamie Madillfeda4d22014-09-17 13:03:29 -04001904Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1905{
1906 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1907 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1908 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1909 return mImageArray[index.mipIndex][index.layerIndex];
1910}
1911
Brandon Jones142ec422014-07-16 10:31:30 -07001912GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1913{
1914 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1915 return mLayerCounts[level];
1916}
1917
Brandon Jones142ec422014-07-16 10:31:30 -07001918GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1919{
1920 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1921}
1922
1923GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1924{
1925 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1926}
1927
1928GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1929{
1930 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1931}
1932
1933GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1934{
1935 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1936}
1937
1938bool TextureD3D_2DArray::isDepth(GLint level) const
1939{
Geoff Lang5d601382014-07-22 15:14:06 -04001940 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001941}
1942
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001943gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1944 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1945 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001946{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001947 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1948
Geoff Lang5d601382014-07-22 15:14:06 -04001949 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1950
Brandon Jones142ec422014-07-16 10:31:30 -07001951 redefineImage(level, sizedInternalFormat, width, height, depth);
1952
Geoff Lang5d601382014-07-22 15:14:06 -04001953 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1954 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001955
1956 for (int i = 0; i < depth; i++)
1957 {
1958 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001959 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1960 if (error.isError())
1961 {
1962 return error;
1963 }
Brandon Jones142ec422014-07-16 10:31:30 -07001964 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001965
1966 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001967}
1968
Brandon Jonescef06ff2014-08-05 13:27:48 -07001969void 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 -07001970{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001971 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1972
Brandon Jones142ec422014-07-16 10:31:30 -07001973 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1974 redefineImage(level, format, width, height, depth);
1975
Geoff Lang5d601382014-07-22 15:14:06 -04001976 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1977 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001978
1979 for (int i = 0; i < depth; i++)
1980 {
1981 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1982 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1983 }
1984}
1985
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001986gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1987 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1988 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001989{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001990 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1991
Geoff Lang5d601382014-07-22 15:14:06 -04001992 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1993 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001994
1995 for (int i = 0; i < depth; i++)
1996 {
1997 int layer = zoffset + i;
1998 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1999
Jamie Madillfeda4d22014-09-17 13:03:29 -04002000 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002001 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2002 layerPixels, index);
2003 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002004 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002005 return error;
2006 }
2007
2008 error = commitRect(level, xoffset, yoffset, layer, width, height);
2009 if (error.isError())
2010 {
2011 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002012 }
2013 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002014
2015 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002016}
2017
Brandon Jonescef06ff2014-08-05 13:27:48 -07002018void 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 -07002019{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002020 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2021
Geoff Lang5d601382014-07-22 15:14:06 -04002022 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2023 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002024
2025 for (int i = 0; i < depth; i++)
2026 {
2027 int layer = zoffset + i;
2028 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2029
2030 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2031 {
2032 commitRect(level, xoffset, yoffset, layer, width, height);
2033 }
2034 }
2035}
2036
Brandon Jonescef06ff2014-08-05 13:27:48 -07002037void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2038{
2039 UNIMPLEMENTED();
2040}
2041
Brandon Jones142ec422014-07-16 10:31:30 -07002042void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2043{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002044 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2045
Brandon Jones142ec422014-07-16 10:31:30 -07002046 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2047 // the current level we're copying to is defined (with appropriate format, width & height)
2048 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2049
2050 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2051 {
2052 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2053 mDirtyImages = true;
2054 }
2055 else
2056 {
2057 ensureRenderTarget();
2058
2059 if (isValidLevel(level))
2060 {
2061 updateStorageLevel(level);
2062
2063 gl::Rectangle sourceRect;
2064 sourceRect.x = x;
2065 sourceRect.width = width;
2066 sourceRect.y = y;
2067 sourceRect.height = height;
2068
Jamie Madill856d9d42014-09-18 15:08:49 -04002069 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2070 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002071 }
2072 }
2073}
2074
Brandon Jonescef06ff2014-08-05 13:27:48 -07002075void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002076{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002077 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2078
Brandon Jones142ec422014-07-16 10:31:30 -07002079 deleteImages();
2080
2081 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2082 {
2083 GLsizei levelWidth = std::max(1, width >> level);
2084 GLsizei levelHeight = std::max(1, height >> level);
2085
2086 mLayerCounts[level] = (level < levels ? depth : 0);
2087
2088 if (mLayerCounts[level] > 0)
2089 {
2090 // Create new images for this level
2091 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2092
2093 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2094 {
2095 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2096 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2097 levelHeight, 1, true);
2098 }
2099 }
2100 }
2101
2102 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002103
2104 bool renderTarget = IsRenderTargetUsage(mUsage);
2105 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002106 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002107}
2108
Brandon Jones6053a522014-07-25 16:22:09 -07002109void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002110{
Brandon Jones6053a522014-07-25 16:22:09 -07002111 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002112}
2113
Brandon Jones6053a522014-07-25 16:22:09 -07002114void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002115{
Brandon Jones6053a522014-07-25 16:22:09 -07002116 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002117}
2118
Brandon Jones6053a522014-07-25 16:22:09 -07002119
Jamie Madill4aa79e12014-09-29 10:46:14 -04002120void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002121{
2122 int baseWidth = getBaseLevelWidth();
2123 int baseHeight = getBaseLevelHeight();
2124 int baseDepth = getBaseLevelDepth();
2125 GLenum baseFormat = getBaseLevelInternalFormat();
2126
2127 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2128 int levelCount = mipLevels();
2129 for (int level = 1; level < levelCount; level++)
2130 {
2131 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2132 }
Brandon Jones142ec422014-07-16 10:31:30 -07002133}
2134
Jamie Madillac7579c2014-09-17 16:59:33 -04002135unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002136{
Jamie Madillc4833262014-09-18 16:18:26 -04002137 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002138}
2139
Jamie Madillac7579c2014-09-17 16:59:33 -04002140RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002141{
2142 // ensure the underlying texture is created
2143 if (!ensureRenderTarget())
2144 {
2145 return NULL;
2146 }
2147
Jamie Madillac7579c2014-09-17 16:59:33 -04002148 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002149 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002150}
2151
2152void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2153{
2154 // Only initialize the first time this texture is used as a render target or shader resource
2155 if (mTexStorage)
2156 {
2157 return;
2158 }
2159
2160 // do not attempt to create storage for nonexistant data
2161 if (!isLevelComplete(0))
2162 {
2163 return;
2164 }
2165
2166 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2167
2168 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2169 ASSERT(mTexStorage);
2170
2171 // flush image data to the storage
2172 updateStorage();
2173}
2174
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002175TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002176{
2177 GLsizei width = getBaseLevelWidth();
2178 GLsizei height = getBaseLevelHeight();
2179 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002180 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002181
2182 ASSERT(width > 0 && height > 0 && depth > 0);
2183
2184 // use existing storage level count, when previously specified by TexStorage*D
2185 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2186
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002187 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002188}
2189
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002190void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002191{
2192 SafeDelete(mTexStorage);
2193 mTexStorage = newCompleteTexStorage;
2194 mDirtyImages = true;
2195
2196 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2197 ASSERT(!mTexStorage->isManaged());
2198}
2199
2200void TextureD3D_2DArray::updateStorage()
2201{
2202 ASSERT(mTexStorage != NULL);
2203 GLint storageLevels = mTexStorage->getLevelCount();
2204 for (int level = 0; level < storageLevels; level++)
2205 {
2206 if (isLevelComplete(level))
2207 {
2208 updateStorageLevel(level);
2209 }
2210 }
2211}
2212
2213bool TextureD3D_2DArray::ensureRenderTarget()
2214{
2215 initializeStorage(true);
2216
2217 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2218 {
2219 ASSERT(mTexStorage);
2220 if (!mTexStorage->isRenderTarget())
2221 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002222 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002223
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002224 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002225 {
2226 delete newRenderTargetStorage;
2227 return gl::error(GL_OUT_OF_MEMORY, false);
2228 }
2229
2230 setCompleteTexStorage(newRenderTargetStorage);
2231 }
2232 }
2233
2234 return (mTexStorage && mTexStorage->isRenderTarget());
2235}
2236
2237const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2238{
2239 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2240}
2241
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002242TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002243{
2244 return mTexStorage;
2245}
2246
2247bool TextureD3D_2DArray::isValidLevel(int level) const
2248{
2249 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2250}
2251
2252bool TextureD3D_2DArray::isLevelComplete(int level) const
2253{
2254 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2255
2256 if (isImmutable())
2257 {
2258 return true;
2259 }
2260
2261 GLsizei width = getBaseLevelWidth();
2262 GLsizei height = getBaseLevelHeight();
2263 GLsizei layers = getLayers(0);
2264
2265 if (width <= 0 || height <= 0 || layers <= 0)
2266 {
2267 return false;
2268 }
2269
2270 if (level == 0)
2271 {
2272 return true;
2273 }
2274
2275 if (getInternalFormat(level) != getInternalFormat(0))
2276 {
2277 return false;
2278 }
2279
2280 if (getWidth(level) != std::max(1, width >> level))
2281 {
2282 return false;
2283 }
2284
2285 if (getHeight(level) != std::max(1, height >> level))
2286 {
2287 return false;
2288 }
2289
2290 if (getLayers(level) != layers)
2291 {
2292 return false;
2293 }
2294
2295 return true;
2296}
2297
2298void TextureD3D_2DArray::updateStorageLevel(int level)
2299{
2300 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2301 ASSERT(isLevelComplete(level));
2302
2303 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2304 {
2305 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2306 if (mImageArray[level][layer]->isDirty())
2307 {
2308 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2309 }
2310 }
2311}
2312
2313void TextureD3D_2DArray::deleteImages()
2314{
2315 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2316 {
2317 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2318 {
2319 delete mImageArray[level][layer];
2320 }
2321 delete[] mImageArray[level];
2322 mImageArray[level] = NULL;
2323 mLayerCounts[level] = 0;
2324 }
2325}
2326
2327void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2328{
2329 // If there currently is a corresponding storage texture image, it has these parameters
2330 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2331 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2332 const int storageDepth = getLayers(0);
2333 const GLenum storageFormat = getBaseLevelInternalFormat();
2334
2335 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2336 {
2337 delete mImageArray[level][layer];
2338 }
2339 delete[] mImageArray[level];
2340 mImageArray[level] = NULL;
2341 mLayerCounts[level] = depth;
2342
2343 if (depth > 0)
2344 {
2345 mImageArray[level] = new ImageD3D*[depth]();
2346
2347 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2348 {
2349 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2350 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2351 }
2352 }
2353
2354 if (mTexStorage)
2355 {
2356 const int storageLevels = mTexStorage->getLevelCount();
2357
2358 if ((level >= storageLevels && storageLevels != 0) ||
2359 width != storageWidth ||
2360 height != storageHeight ||
2361 depth != storageDepth ||
2362 internalformat != storageFormat) // Discard mismatched storage
2363 {
2364 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2365 {
2366 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2367 {
2368 mImageArray[level][layer]->markDirty();
2369 }
2370 }
2371
2372 delete mTexStorage;
2373 mTexStorage = NULL;
2374 mDirtyImages = true;
2375 }
2376 }
2377}
2378
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002379gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
Brandon Jones142ec422014-07-16 10:31:30 -07002380{
2381 if (isValidLevel(level) && layerTarget < getLayers(level))
2382 {
2383 ImageD3D *image = mImageArray[level][layerTarget];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002384 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
2385 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002386 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002387 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002388 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002389
2390 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002391 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002392
2393 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002394}
2395
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002396gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2397{
2398 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2399}
2400
Jamie Madillcb83dc12014-09-29 10:46:12 -04002401gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2402{
2403 return gl::ImageIndex::Make2DArray(mip, layer);
2404}
2405
Brandon Jones78b1acd2014-07-15 15:33:07 -07002406}