blob: 52e896eb3c60c53d5785c2294e6e1412dd8383af [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
Geoff Langb5348332014-09-02 13:16:34 -0400164gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165{
166 if (pixels != NULL)
167 {
Geoff Langb5348332014-09-02 13:16:34 -0400168 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
169 if (error.isError())
170 {
171 return error;
172 }
173
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174 mDirtyImages = true;
175 }
Geoff Langb5348332014-09-02 13:16:34 -0400176
177 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700178}
179
Geoff Langb5348332014-09-02 13:16:34 -0400180gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700181 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700182{
183 if (pixels != NULL)
184 {
Geoff Langb5348332014-09-02 13:16:34 -0400185 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
186 if (error.isError())
187 {
188 return error;
189 }
190
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191 mDirtyImages = true;
192 }
193
Geoff Langb5348332014-09-02 13:16:34 -0400194 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195}
196
197bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
198{
199 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
200}
201
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400202gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
203 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700204{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400205 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700206 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
207 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400208 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700209 }
210
211 // In order to perform the fast copy through the shader, we must have the right format, and be able
212 // to create a render target.
213 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
214
215 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
216
Geoff Langae5122c2014-08-27 14:08:43 -0400217 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
218 if (error.isError())
219 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400220 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400221 }
222
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400223 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700224}
225
226GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
227{
228 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
229 {
230 // Maximum number of levels
231 return gl::log2(std::max(std::max(width, height), depth)) + 1;
232 }
233 else
234 {
235 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
236 return 1;
237 }
238}
239
240int TextureD3D::mipLevels() const
241{
242 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
243}
244
Jamie Madill4aa79e12014-09-29 10:46:14 -0400245void TextureD3D::generateMipmaps()
246{
247 // Set up proper image sizes.
248 initMipmapsImages();
249
250 // We know that all layers have the same dimension, for the texture to be complete
251 GLint layerCount = static_cast<GLint>(getLayerCount(0));
252 GLint mipCount = mipLevels();
253
254 // The following will create and initialize the storage, or update it if it exists
255 TextureStorage *storage = getNativeTexture();
256
257 bool renderableStorage = (storage && storage->isRenderTarget());
258
259 for (GLint layer = 0; layer < layerCount; ++layer)
260 {
261 for (GLint mip = 1; mip < mipCount; ++mip)
262 {
263 ASSERT(getLayerCount(mip) == layerCount);
264
265 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
266 gl::ImageIndex destIndex = getImageIndex(mip, layer);
267
268 if (renderableStorage)
269 {
270 // GPU-side mipmapping
271 storage->generateMipmap(sourceIndex, destIndex);
272 }
273 else
274 {
275 // CPU-side mipmapping
276 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
277 }
278 }
279 }
280}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700281
Brandon Jones78b1acd2014-07-15 15:33:07 -0700282TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700283 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700284 mTexStorage(NULL)
285{
286 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
287 {
288 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
289 }
290}
291
292TextureD3D_2D::~TextureD3D_2D()
293{
Austin Kinross69822602014-08-12 15:51:37 -0700294 // Delete the Images before the TextureStorage.
295 // Images might be relying on the TextureStorage for some of their data.
296 // 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 -0700297 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
298 {
299 delete mImageArray[i];
300 }
Austin Kinross69822602014-08-12 15:51:37 -0700301
302 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700303}
304
Brandon Jonescef06ff2014-08-05 13:27:48 -0700305Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700306{
307 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700308 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700309 return mImageArray[level];
310}
311
Jamie Madillfeda4d22014-09-17 13:03:29 -0400312Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
313{
314 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400315 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400316 ASSERT(index.type == GL_TEXTURE_2D);
317 return mImageArray[index.mipIndex];
318}
319
Brandon Jonescef06ff2014-08-05 13:27:48 -0700320GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700321{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700322 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
323 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700324}
325
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700326GLsizei TextureD3D_2D::getWidth(GLint level) const
327{
328 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
329 return mImageArray[level]->getWidth();
330 else
331 return 0;
332}
333
334GLsizei TextureD3D_2D::getHeight(GLint level) const
335{
336 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
337 return mImageArray[level]->getHeight();
338 else
339 return 0;
340}
341
342GLenum TextureD3D_2D::getInternalFormat(GLint level) const
343{
344 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
345 return mImageArray[level]->getInternalFormat();
346 else
347 return GL_NONE;
348}
349
350GLenum TextureD3D_2D::getActualFormat(GLint level) const
351{
352 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
353 return mImageArray[level]->getActualFormat();
354 else
355 return GL_NONE;
356}
357
358bool TextureD3D_2D::isDepth(GLint level) const
359{
Geoff Lang5d601382014-07-22 15:14:06 -0400360 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700361}
362
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400363gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
364 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
365 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700366{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700367 ASSERT(target == GL_TEXTURE_2D && depth == 1);
368
Geoff Lang5d601382014-07-22 15:14:06 -0400369 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
370
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700371 bool fastUnpacked = false;
372
Brandon Jonescef06ff2014-08-05 13:27:48 -0700373 redefineImage(level, sizedInternalFormat, width, height);
374
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700375 // Attempt a fast gpu copy of the pixel data to the surface
376 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
377 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400378 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
379
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700380 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400381 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700382 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
383
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400384 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700385 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400386 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
387 if (error.isError())
388 {
389 return error;
390 }
391
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700392 // Ensure we don't overwrite our newly initialized data
393 mImageArray[level]->markClean();
394
395 fastUnpacked = true;
396 }
397 }
398
399 if (!fastUnpacked)
400 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400401 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
402 if (error.isError())
403 {
404 return error;
405 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700406 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400407
408 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700409}
410
Geoff Langb5348332014-09-02 13:16:34 -0400411gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
412 GLsizei width, GLsizei height, GLsizei depth,
413 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700414{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700415 ASSERT(target == GL_TEXTURE_2D && depth == 1);
416
417 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
418 redefineImage(level, format, width, height);
419
Geoff Langb5348332014-09-02 13:16:34 -0400420 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421}
422
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400423gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
424 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
425 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700426{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700427 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
428
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700429 bool fastUnpacked = false;
430
Jamie Madillac7579c2014-09-17 16:59:33 -0400431 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700432 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
433 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400434 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
436
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400437 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700438 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400439 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
440 if (error.isError())
441 {
442 return error;
443 }
444
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700445 // Ensure we don't overwrite our newly initialized data
446 mImageArray[level]->markClean();
447
448 fastUnpacked = true;
449 }
450 }
451
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400452 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700453 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400454 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
455 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
456 pixels, index);
457 if (error.isError())
458 {
459 return error;
460 }
461
462 error = commitRect(level, xoffset, yoffset, width, height);
463 if (error.isError())
464 {
465 return error;
466 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700467 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400468
469 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700470}
471
Geoff Langb5348332014-09-02 13:16:34 -0400472gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
473 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
474 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700475{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700476 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
477
Geoff Langb5348332014-09-02 13:16:34 -0400478 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
479 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700480 {
Geoff Langb5348332014-09-02 13:16:34 -0400481 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700482 }
Geoff Langb5348332014-09-02 13:16:34 -0400483
484 error = commitRect(level, xoffset, yoffset, width, height);
485 if (error.isError())
486 {
487 return error;
488 }
489
490 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700491}
492
Brandon Jonescef06ff2014-08-05 13:27:48 -0700493void 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 -0700494{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700495 ASSERT(target == GL_TEXTURE_2D);
496
497 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
498 redefineImage(level, sizedInternalFormat, width, height);
499
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700500 if (!mImageArray[level]->isRenderableFormat())
501 {
502 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
503 mDirtyImages = true;
504 }
505 else
506 {
507 ensureRenderTarget();
508 mImageArray[level]->markClean();
509
510 if (width != 0 && height != 0 && isValidLevel(level))
511 {
512 gl::Rectangle sourceRect;
513 sourceRect.x = x;
514 sourceRect.width = width;
515 sourceRect.y = y;
516 sourceRect.height = height;
517
Jamie Madill856d9d42014-09-18 15:08:49 -0400518 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519 }
520 }
521}
522
523void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
524{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700525 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
526
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700527 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
528 // the current level we're copying to is defined (with appropriate format, width & height)
529 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
530
531 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
532 {
533 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
534 mDirtyImages = true;
535 }
536 else
537 {
538 ensureRenderTarget();
539
540 if (isValidLevel(level))
541 {
542 updateStorageLevel(level);
543
544 gl::Rectangle sourceRect;
545 sourceRect.x = x;
546 sourceRect.width = width;
547 sourceRect.y = y;
548 sourceRect.height = height;
549
Jamie Madill856d9d42014-09-18 15:08:49 -0400550 mRenderer->copyImage2D(source, sourceRect,
551 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
552 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700553 }
554 }
555}
556
Brandon Jonescef06ff2014-08-05 13:27:48 -0700557void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700559 ASSERT(target == GL_TEXTURE_2D && depth == 1);
560
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700561 for (int level = 0; level < levels; level++)
562 {
563 GLsizei levelWidth = std::max(1, width >> level);
564 GLsizei levelHeight = std::max(1, height >> level);
565 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
566 }
567
568 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
569 {
570 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
571 }
572
573 mImmutable = true;
574
Jamie Madillc4833262014-09-18 16:18:26 -0400575 bool renderTarget = IsRenderTargetUsage(mUsage);
576 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400577 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700578}
579
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700580void TextureD3D_2D::bindTexImage(egl::Surface *surface)
581{
582 GLenum internalformat = surface->getFormat();
583
584 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
585
586 if (mTexStorage)
587 {
588 SafeDelete(mTexStorage);
589 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400590
591 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700592
593 mDirtyImages = true;
594}
595
596void TextureD3D_2D::releaseTexImage()
597{
598 if (mTexStorage)
599 {
600 SafeDelete(mTexStorage);
601 }
602
603 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
604 {
605 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
606 }
607}
608
Jamie Madill4aa79e12014-09-29 10:46:14 -0400609void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700611 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700612 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700613 for (int level = 1; level < levelCount; level++)
614 {
615 redefineImage(level, getBaseLevelInternalFormat(),
616 std::max(getBaseLevelWidth() >> level, 1),
617 std::max(getBaseLevelHeight() >> level, 1));
618 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619}
620
Jamie Madillac7579c2014-09-17 16:59:33 -0400621unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622{
Jamie Madillac7579c2014-09-17 16:59:33 -0400623 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400624 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625}
626
Jamie Madillac7579c2014-09-17 16:59:33 -0400627RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700628{
Jamie Madillac7579c2014-09-17 16:59:33 -0400629 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700630
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631 // ensure the underlying texture is created
632 if (!ensureRenderTarget())
633 {
634 return NULL;
635 }
636
Jamie Madillac7579c2014-09-17 16:59:33 -0400637 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400638 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639}
640
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700641bool TextureD3D_2D::isValidLevel(int level) const
642{
643 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
644}
645
646bool TextureD3D_2D::isLevelComplete(int level) const
647{
648 if (isImmutable())
649 {
650 return true;
651 }
652
Brandon Jones78b1acd2014-07-15 15:33:07 -0700653 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654
655 GLsizei width = baseImage->getWidth();
656 GLsizei height = baseImage->getHeight();
657
658 if (width <= 0 || height <= 0)
659 {
660 return false;
661 }
662
663 // The base image level is complete if the width and height are positive
664 if (level == 0)
665 {
666 return true;
667 }
668
669 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700670 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671
672 if (image->getInternalFormat() != baseImage->getInternalFormat())
673 {
674 return false;
675 }
676
677 if (image->getWidth() != std::max(1, width >> level))
678 {
679 return false;
680 }
681
682 if (image->getHeight() != std::max(1, height >> level))
683 {
684 return false;
685 }
686
687 return true;
688}
689
690// Constructs a native texture resource from the texture images
691void TextureD3D_2D::initializeStorage(bool renderTarget)
692{
693 // Only initialize the first time this texture is used as a render target or shader resource
694 if (mTexStorage)
695 {
696 return;
697 }
698
699 // do not attempt to create storage for nonexistant data
700 if (!isLevelComplete(0))
701 {
702 return;
703 }
704
705 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
706
707 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
708 ASSERT(mTexStorage);
709
710 // flush image data to the storage
711 updateStorage();
712}
713
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400714TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700715{
716 GLsizei width = getBaseLevelWidth();
717 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400718 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700719
720 ASSERT(width > 0 && height > 0);
721
722 // use existing storage level count, when previously specified by TexStorage*D
723 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
724
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400725 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700726}
727
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400728void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700729{
730 SafeDelete(mTexStorage);
731 mTexStorage = newCompleteTexStorage;
732
733 if (mTexStorage && mTexStorage->isManaged())
734 {
735 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
736 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400737 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700738 }
739 }
740
741 mDirtyImages = true;
742}
743
744void TextureD3D_2D::updateStorage()
745{
746 ASSERT(mTexStorage != NULL);
747 GLint storageLevels = mTexStorage->getLevelCount();
748 for (int level = 0; level < storageLevels; level++)
749 {
750 if (mImageArray[level]->isDirty() && isLevelComplete(level))
751 {
752 updateStorageLevel(level);
753 }
754 }
755}
756
757bool TextureD3D_2D::ensureRenderTarget()
758{
759 initializeStorage(true);
760
761 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
762 {
763 ASSERT(mTexStorage);
764 if (!mTexStorage->isRenderTarget())
765 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400766 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700767
Geoff Lang9e3f24f2014-08-27 12:06:04 -0400768 if (mRenderer->copyToRenderTarget2D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700769 {
770 delete newRenderTargetStorage;
771 return gl::error(GL_OUT_OF_MEMORY, false);
772 }
773
774 setCompleteTexStorage(newRenderTargetStorage);
775 }
776 }
777
778 return (mTexStorage && mTexStorage->isRenderTarget());
779}
780
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400781TextureStorage *TextureD3D_2D::getBaseLevelStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700782{
783 return mTexStorage;
784}
785
786const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
787{
788 return mImageArray[0];
789}
790
791void TextureD3D_2D::updateStorageLevel(int level)
792{
793 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
794 ASSERT(isLevelComplete(level));
795
796 if (mImageArray[level]->isDirty())
797 {
798 commitRect(level, 0, 0, getWidth(level), getHeight(level));
799 }
800}
801
802void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
803{
804 // If there currently is a corresponding storage texture image, it has these parameters
805 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
806 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
807 const GLenum storageFormat = getBaseLevelInternalFormat();
808
809 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
810
811 if (mTexStorage)
812 {
813 const int storageLevels = mTexStorage->getLevelCount();
814
815 if ((level >= storageLevels && storageLevels != 0) ||
816 width != storageWidth ||
817 height != storageHeight ||
818 internalformat != storageFormat) // Discard mismatched storage
819 {
820 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
821 {
822 mImageArray[i]->markDirty();
823 }
824
825 SafeDelete(mTexStorage);
826 mDirtyImages = true;
827 }
828 }
829}
830
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400831gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700832{
833 if (isValidLevel(level))
834 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700835 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400836 gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
837 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700838 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400839 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700840 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400841
842 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700843 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400844
845 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700846}
847
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400848gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
849{
850 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
851}
Brandon Jones0511e802014-07-14 16:27:26 -0700852
Jamie Madillcb83dc12014-09-29 10:46:12 -0400853gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
854{
855 // "layer" does not apply to 2D Textures.
856 return gl::ImageIndex::Make2D(mip);
857}
858
Brandon Jones78b1acd2014-07-15 15:33:07 -0700859TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700860 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700861 mTexStorage(NULL)
862{
863 for (int i = 0; i < 6; i++)
864 {
865 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
866 {
867 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
868 }
869 }
870}
871
872TextureD3D_Cube::~TextureD3D_Cube()
873{
Austin Kinross69822602014-08-12 15:51:37 -0700874 // Delete the Images before the TextureStorage.
875 // Images might be relying on the TextureStorage for some of their data.
876 // 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 -0700877 for (int i = 0; i < 6; i++)
878 {
879 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
880 {
881 SafeDelete(mImageArray[i][j]);
882 }
883 }
Austin Kinross69822602014-08-12 15:51:37 -0700884
885 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700886}
887
Brandon Jonescef06ff2014-08-05 13:27:48 -0700888Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700889{
890 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700891 ASSERT(layer < 6);
892 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700893}
894
Jamie Madillfeda4d22014-09-17 13:03:29 -0400895Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
896{
897 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
898 ASSERT(index.layerIndex < 6);
899 return mImageArray[index.layerIndex][index.mipIndex];
900}
901
Brandon Jonescef06ff2014-08-05 13:27:48 -0700902GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700903{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700904 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
905 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700906}
907
Brandon Jonescef06ff2014-08-05 13:27:48 -0700908GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700909{
910 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700911 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700912 else
913 return GL_NONE;
914}
915
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700917{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700918 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700919}
920
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400921gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
922 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
923 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700924{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700925 ASSERT(depth == 1);
926
927 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400928 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700929
930 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
931
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400932 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700933}
934
Geoff Langb5348332014-09-02 13:16:34 -0400935gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
936 GLsizei width, GLsizei height, GLsizei depth,
937 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700938{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700939 ASSERT(depth == 1);
940
Brandon Jones0511e802014-07-14 16:27:26 -0700941 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700942 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
943
Brandon Jones0511e802014-07-14 16:27:26 -0700944 redefineImage(faceIndex, level, format, width, height);
945
Geoff Langb5348332014-09-02 13:16:34 -0400946 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700947}
948
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400949gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
950 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
951 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700952{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700953 ASSERT(depth == 1 && zoffset == 0);
954
955 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
956
Jamie Madillfeda4d22014-09-17 13:03:29 -0400957 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400958 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
959 index);
960 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700961 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400962 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700963 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400964
965 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
966 if (error.isError())
967 {
968 return error;
969 }
970
971 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700972}
973
Geoff Langb5348332014-09-02 13:16:34 -0400974gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
975 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
976 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700977{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700978 ASSERT(depth == 1 && zoffset == 0);
979
980 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
981
Geoff Langb5348332014-09-02 13:16:34 -0400982 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]);
983 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700984 {
Geoff Langb5348332014-09-02 13:16:34 -0400985 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700986 }
Geoff Langb5348332014-09-02 13:16:34 -0400987
988 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
989 if (error.isError())
990 {
991 return error;
992 }
993
994 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700995}
996
997void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
998{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700999 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001000 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1001
Brandon Jones0511e802014-07-14 16:27:26 -07001002 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1003
1004 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1005 {
1006 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1007 mDirtyImages = true;
1008 }
1009 else
1010 {
1011 ensureRenderTarget();
1012 mImageArray[faceIndex][level]->markClean();
1013
1014 ASSERT(width == height);
1015
1016 if (width > 0 && isValidFaceLevel(faceIndex, level))
1017 {
1018 gl::Rectangle sourceRect;
1019 sourceRect.x = x;
1020 sourceRect.width = width;
1021 sourceRect.y = y;
1022 sourceRect.height = height;
1023
Jamie Madill856d9d42014-09-18 15:08:49 -04001024 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001025 }
1026 }
1027}
1028
1029void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1030{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001031 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001032
1033 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1034 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1035 // rely on the "getBaseLevel*" methods reliably otherwise.
1036 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1037
1038 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1039 {
1040 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1041 mDirtyImages = true;
1042 }
1043 else
1044 {
1045 ensureRenderTarget();
1046
1047 if (isValidFaceLevel(faceIndex, level))
1048 {
1049 updateStorageFaceLevel(faceIndex, level);
1050
1051 gl::Rectangle sourceRect;
1052 sourceRect.x = x;
1053 sourceRect.width = width;
1054 sourceRect.y = y;
1055 sourceRect.height = height;
1056
Jamie Madill856d9d42014-09-18 15:08:49 -04001057 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1058 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001059 }
1060 }
1061}
1062
Brandon Jonescef06ff2014-08-05 13:27:48 -07001063void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001064{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001065 ASSERT(width == height);
1066 ASSERT(depth == 1);
1067
Brandon Jones0511e802014-07-14 16:27:26 -07001068 for (int level = 0; level < levels; level++)
1069 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001070 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001071 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1072 {
1073 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1074 }
1075 }
1076
1077 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1078 {
1079 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1080 {
1081 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1082 }
1083 }
1084
1085 mImmutable = true;
1086
Jamie Madillc4833262014-09-18 16:18:26 -04001087 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001088 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1089 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001090}
1091
Brandon Jones0511e802014-07-14 16:27:26 -07001092// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1093bool TextureD3D_Cube::isCubeComplete() const
1094{
1095 int baseWidth = getBaseLevelWidth();
1096 int baseHeight = getBaseLevelHeight();
1097 GLenum baseFormat = getBaseLevelInternalFormat();
1098
1099 if (baseWidth <= 0 || baseWidth != baseHeight)
1100 {
1101 return false;
1102 }
1103
1104 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1105 {
1106 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1107
1108 if (faceBaseImage.getWidth() != baseWidth ||
1109 faceBaseImage.getHeight() != baseHeight ||
1110 faceBaseImage.getInternalFormat() != baseFormat )
1111 {
1112 return false;
1113 }
1114 }
1115
1116 return true;
1117}
1118
Brandon Jones6053a522014-07-25 16:22:09 -07001119void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1120{
1121 UNREACHABLE();
1122}
1123
1124void TextureD3D_Cube::releaseTexImage()
1125{
1126 UNREACHABLE();
1127}
1128
1129
Jamie Madill4aa79e12014-09-29 10:46:14 -04001130void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001131{
1132 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1133 int levelCount = mipLevels();
1134 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1135 {
1136 for (int level = 1; level < levelCount; level++)
1137 {
1138 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1139 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1140 }
1141 }
Brandon Jones0511e802014-07-14 16:27:26 -07001142}
1143
Jamie Madillac7579c2014-09-17 16:59:33 -04001144unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001145{
Jamie Madillc4833262014-09-18 16:18:26 -04001146 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001147}
1148
Jamie Madillac7579c2014-09-17 16:59:33 -04001149RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001150{
Jamie Madillac7579c2014-09-17 16:59:33 -04001151 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001152
1153 // ensure the underlying texture is created
1154 if (!ensureRenderTarget())
1155 {
1156 return NULL;
1157 }
1158
Jamie Madillac7579c2014-09-17 16:59:33 -04001159 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001160 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001161}
1162
Brandon Jones0511e802014-07-14 16:27:26 -07001163void TextureD3D_Cube::initializeStorage(bool renderTarget)
1164{
1165 // Only initialize the first time this texture is used as a render target or shader resource
1166 if (mTexStorage)
1167 {
1168 return;
1169 }
1170
1171 // do not attempt to create storage for nonexistant data
1172 if (!isFaceLevelComplete(0, 0))
1173 {
1174 return;
1175 }
1176
1177 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1178
1179 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1180 ASSERT(mTexStorage);
1181
1182 // flush image data to the storage
1183 updateStorage();
1184}
1185
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001186TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001187{
1188 GLsizei size = getBaseLevelWidth();
1189
1190 ASSERT(size > 0);
1191
1192 // use existing storage level count, when previously specified by TexStorage*D
1193 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1194
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001195 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001196}
1197
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001198void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001199{
1200 SafeDelete(mTexStorage);
1201 mTexStorage = newCompleteTexStorage;
1202
1203 if (mTexStorage && mTexStorage->isManaged())
1204 {
1205 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1206 {
1207 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1208 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001209 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001210 }
1211 }
1212 }
1213
1214 mDirtyImages = true;
1215}
1216
1217void TextureD3D_Cube::updateStorage()
1218{
1219 ASSERT(mTexStorage != NULL);
1220 GLint storageLevels = mTexStorage->getLevelCount();
1221 for (int face = 0; face < 6; face++)
1222 {
1223 for (int level = 0; level < storageLevels; level++)
1224 {
1225 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1226 {
1227 updateStorageFaceLevel(face, level);
1228 }
1229 }
1230 }
1231}
1232
1233bool TextureD3D_Cube::ensureRenderTarget()
1234{
1235 initializeStorage(true);
1236
1237 if (getBaseLevelWidth() > 0)
1238 {
1239 ASSERT(mTexStorage);
1240 if (!mTexStorage->isRenderTarget())
1241 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001242 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001243
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001244 if (mRenderer->copyToRenderTargetCube(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001245 {
1246 delete newRenderTargetStorage;
1247 return gl::error(GL_OUT_OF_MEMORY, false);
1248 }
1249
1250 setCompleteTexStorage(newRenderTargetStorage);
1251 }
1252 }
1253
1254 return (mTexStorage && mTexStorage->isRenderTarget());
1255}
1256
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001257TextureStorage *TextureD3D_Cube::getBaseLevelStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001258{
1259 return mTexStorage;
1260}
1261
1262const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1263{
1264 // Note: if we are not cube-complete, there is no single base level image that can describe all
1265 // cube faces, so this method is only well-defined for a cube-complete base level.
1266 return mImageArray[0][0];
1267}
1268
Brandon Jones0511e802014-07-14 16:27:26 -07001269bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1270{
1271 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1272}
1273
Brandon Jones0511e802014-07-14 16:27:26 -07001274bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1275{
1276 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1277
1278 if (isImmutable())
1279 {
1280 return true;
1281 }
1282
1283 int baseSize = getBaseLevelWidth();
1284
1285 if (baseSize <= 0)
1286 {
1287 return false;
1288 }
1289
1290 // "isCubeComplete" checks for base level completeness and we must call that
1291 // to determine if any face at level 0 is complete. We omit that check here
1292 // to avoid re-checking cube-completeness for every face at level 0.
1293 if (level == 0)
1294 {
1295 return true;
1296 }
1297
1298 // Check that non-zero levels are consistent with the base level.
1299 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1300
1301 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1302 {
1303 return false;
1304 }
1305
1306 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1307 {
1308 return false;
1309 }
1310
1311 return true;
1312}
1313
1314void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1315{
1316 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1317 ImageD3D *image = mImageArray[faceIndex][level];
1318
1319 if (image->isDirty())
1320 {
1321 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1322 }
1323}
1324
1325void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1326{
1327 // If there currently is a corresponding storage texture image, it has these parameters
1328 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1329 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1330 const GLenum storageFormat = getBaseLevelInternalFormat();
1331
1332 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1333
1334 if (mTexStorage)
1335 {
1336 const int storageLevels = mTexStorage->getLevelCount();
1337
1338 if ((level >= storageLevels && storageLevels != 0) ||
1339 width != storageWidth ||
1340 height != storageHeight ||
1341 internalformat != storageFormat) // Discard mismatched storage
1342 {
1343 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1344 {
1345 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1346 {
1347 mImageArray[faceIndex][level]->markDirty();
1348 }
1349 }
1350
1351 SafeDelete(mTexStorage);
1352
1353 mDirtyImages = true;
1354 }
1355 }
1356}
1357
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001358gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jones0511e802014-07-14 16:27:26 -07001359{
1360 if (isValidFaceLevel(faceIndex, level))
1361 {
1362 ImageD3D *image = mImageArray[faceIndex][level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001363 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
1364 if (error.isError())
1365 {
1366 return error;
1367 }
1368
1369 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001370 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001371
1372 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001373}
1374
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001375gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1376{
1377 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1378}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001379
Jamie Madillcb83dc12014-09-29 10:46:12 -04001380gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1381{
1382 // The "layer" of the image index corresponds to the cube face
1383 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1384}
1385
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001387 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001388 mTexStorage(NULL)
1389{
1390 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1391 {
1392 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1393 }
1394}
1395
1396TextureD3D_3D::~TextureD3D_3D()
1397{
Austin Kinross69822602014-08-12 15:51:37 -07001398 // Delete the Images before the TextureStorage.
1399 // Images might be relying on the TextureStorage for some of their data.
1400 // 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 -07001401 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1402 {
1403 delete mImageArray[i];
1404 }
Austin Kinross69822602014-08-12 15:51:37 -07001405
1406 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001407}
1408
Brandon Jonescef06ff2014-08-05 13:27:48 -07001409Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001410{
1411 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001412 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413 return mImageArray[level];
1414}
1415
Jamie Madillfeda4d22014-09-17 13:03:29 -04001416Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1417{
1418 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001419 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001420 ASSERT(index.type == GL_TEXTURE_3D);
1421 return mImageArray[index.mipIndex];
1422}
1423
Brandon Jonescef06ff2014-08-05 13:27:48 -07001424GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001425{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001426 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1427 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001428}
1429
Brandon Jones78b1acd2014-07-15 15:33:07 -07001430GLsizei TextureD3D_3D::getWidth(GLint level) const
1431{
1432 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1433 return mImageArray[level]->getWidth();
1434 else
1435 return 0;
1436}
1437
1438GLsizei TextureD3D_3D::getHeight(GLint level) const
1439{
1440 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1441 return mImageArray[level]->getHeight();
1442 else
1443 return 0;
1444}
1445
1446GLsizei TextureD3D_3D::getDepth(GLint level) const
1447{
1448 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1449 return mImageArray[level]->getDepth();
1450 else
1451 return 0;
1452}
1453
1454GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1455{
1456 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1457 return mImageArray[level]->getInternalFormat();
1458 else
1459 return GL_NONE;
1460}
1461
1462bool TextureD3D_3D::isDepth(GLint level) const
1463{
Geoff Lang5d601382014-07-22 15:14:06 -04001464 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001465}
1466
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001467gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1468 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1469 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001470{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001471 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001472 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1473
Brandon Jones78b1acd2014-07-15 15:33:07 -07001474 redefineImage(level, sizedInternalFormat, width, height, depth);
1475
1476 bool fastUnpacked = false;
1477
1478 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1479 if (isFastUnpackable(unpack, sizedInternalFormat))
1480 {
1481 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001482 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1483 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001484 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1485
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001486 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001487 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001488 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1489 if (error.isError())
1490 {
1491 return error;
1492 }
1493
Brandon Jones78b1acd2014-07-15 15:33:07 -07001494 // Ensure we don't overwrite our newly initialized data
1495 mImageArray[level]->markClean();
1496
1497 fastUnpacked = true;
1498 }
1499 }
1500
1501 if (!fastUnpacked)
1502 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001503 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1504 if (error.isError())
1505 {
1506 return error;
1507 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001508 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001509
1510 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511}
1512
Geoff Langb5348332014-09-02 13:16:34 -04001513gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1514 GLsizei width, GLsizei height,GLsizei depth,
1515 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001517 ASSERT(target == GL_TEXTURE_3D);
1518
Brandon Jones78b1acd2014-07-15 15:33:07 -07001519 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1520 redefineImage(level, format, width, height, depth);
1521
Geoff Langb5348332014-09-02 13:16:34 -04001522 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523}
1524
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001525gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1526 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1527 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001528{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001529 ASSERT(target == GL_TEXTURE_3D);
1530
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531 bool fastUnpacked = false;
1532
Jamie Madillac7579c2014-09-17 16:59:33 -04001533 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1534
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1536 if (isFastUnpackable(unpack, getInternalFormat(level)))
1537 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001538 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001539 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1540
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001541 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001542 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001543 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1544 if (error.isError())
1545 {
1546 return error;
1547 }
1548
Brandon Jones78b1acd2014-07-15 15:33:07 -07001549 // Ensure we don't overwrite our newly initialized data
1550 mImageArray[level]->markClean();
1551
1552 fastUnpacked = true;
1553 }
1554 }
1555
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001556 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001557 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001558 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1559 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1560 pixels, index);
1561 if (error.isError())
1562 {
1563 return error;
1564 }
1565
1566 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1567 if (error.isError())
1568 {
1569 return error;
1570 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001571 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001572
1573 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001574}
1575
Geoff Langb5348332014-09-02 13:16:34 -04001576gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1577 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1578 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001579{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001580 ASSERT(target == GL_TEXTURE_3D);
1581
Geoff Langb5348332014-09-02 13:16:34 -04001582 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1583 format, imageSize, pixels, mImageArray[level]);
1584 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001585 {
Geoff Langb5348332014-09-02 13:16:34 -04001586 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001587 }
Geoff Langb5348332014-09-02 13:16:34 -04001588
1589 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1590 if (error.isError())
1591 {
1592 return error;
1593 }
1594
1595 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001596}
1597
Brandon Jonescef06ff2014-08-05 13:27:48 -07001598void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1599{
1600 UNIMPLEMENTED();
1601}
1602
Brandon Jones78b1acd2014-07-15 15:33:07 -07001603void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1604{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001605 ASSERT(target == GL_TEXTURE_3D);
1606
Brandon Jones78b1acd2014-07-15 15:33:07 -07001607 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1608 // the current level we're copying to is defined (with appropriate format, width & height)
1609 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1610
1611 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1612 {
1613 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1614 mDirtyImages = true;
1615 }
1616 else
1617 {
1618 ensureRenderTarget();
1619
1620 if (isValidLevel(level))
1621 {
1622 updateStorageLevel(level);
1623
1624 gl::Rectangle sourceRect;
1625 sourceRect.x = x;
1626 sourceRect.width = width;
1627 sourceRect.y = y;
1628 sourceRect.height = height;
1629
Jamie Madill856d9d42014-09-18 15:08:49 -04001630 mRenderer->copyImage3D(source, sourceRect,
1631 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1632 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001633 }
1634 }
1635}
1636
Brandon Jonescef06ff2014-08-05 13:27:48 -07001637void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001638{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001639 ASSERT(target == GL_TEXTURE_3D);
1640
Brandon Jones78b1acd2014-07-15 15:33:07 -07001641 for (int level = 0; level < levels; level++)
1642 {
1643 GLsizei levelWidth = std::max(1, width >> level);
1644 GLsizei levelHeight = std::max(1, height >> level);
1645 GLsizei levelDepth = std::max(1, depth >> level);
1646 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1647 }
1648
1649 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1650 {
1651 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1652 }
1653
1654 mImmutable = true;
1655
Jamie Madillc4833262014-09-18 16:18:26 -04001656 bool renderTarget = IsRenderTargetUsage(mUsage);
1657 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001658 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001659}
1660
Brandon Jones6053a522014-07-25 16:22:09 -07001661void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001662{
Brandon Jones6053a522014-07-25 16:22:09 -07001663 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001664}
1665
Brandon Jones6053a522014-07-25 16:22:09 -07001666void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001667{
Brandon Jones6053a522014-07-25 16:22:09 -07001668 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001669}
1670
Brandon Jones6053a522014-07-25 16:22:09 -07001671
Jamie Madill4aa79e12014-09-29 10:46:14 -04001672void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001673{
1674 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1675 int levelCount = mipLevels();
1676 for (int level = 1; level < levelCount; level++)
1677 {
1678 redefineImage(level, getBaseLevelInternalFormat(),
1679 std::max(getBaseLevelWidth() >> level, 1),
1680 std::max(getBaseLevelHeight() >> level, 1),
1681 std::max(getBaseLevelDepth() >> level, 1));
1682 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683}
1684
Jamie Madillac7579c2014-09-17 16:59:33 -04001685unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001686{
Jamie Madillc4833262014-09-18 16:18:26 -04001687 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001688}
1689
Jamie Madillac7579c2014-09-17 16:59:33 -04001690RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001691{
1692 // ensure the underlying texture is created
1693 if (!ensureRenderTarget())
1694 {
1695 return NULL;
1696 }
1697
Jamie Madillac7579c2014-09-17 16:59:33 -04001698 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001699 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001700 updateStorage();
1701 }
1702 else
1703 {
1704 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001705 }
1706
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001707 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001708}
1709
1710void TextureD3D_3D::initializeStorage(bool renderTarget)
1711{
1712 // Only initialize the first time this texture is used as a render target or shader resource
1713 if (mTexStorage)
1714 {
1715 return;
1716 }
1717
1718 // do not attempt to create storage for nonexistant data
1719 if (!isLevelComplete(0))
1720 {
1721 return;
1722 }
1723
1724 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1725
1726 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1727 ASSERT(mTexStorage);
1728
1729 // flush image data to the storage
1730 updateStorage();
1731}
1732
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001733TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001734{
1735 GLsizei width = getBaseLevelWidth();
1736 GLsizei height = getBaseLevelHeight();
1737 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001738 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739
1740 ASSERT(width > 0 && height > 0 && depth > 0);
1741
1742 // use existing storage level count, when previously specified by TexStorage*D
1743 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1744
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001745 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001746}
1747
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001748void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001749{
1750 SafeDelete(mTexStorage);
1751 mTexStorage = newCompleteTexStorage;
1752 mDirtyImages = true;
1753
1754 // We do not support managed 3D storage, as that is D3D9/ES2-only
1755 ASSERT(!mTexStorage->isManaged());
1756}
1757
1758void TextureD3D_3D::updateStorage()
1759{
1760 ASSERT(mTexStorage != NULL);
1761 GLint storageLevels = mTexStorage->getLevelCount();
1762 for (int level = 0; level < storageLevels; level++)
1763 {
1764 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1765 {
1766 updateStorageLevel(level);
1767 }
1768 }
1769}
1770
1771bool TextureD3D_3D::ensureRenderTarget()
1772{
1773 initializeStorage(true);
1774
1775 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1776 {
1777 ASSERT(mTexStorage);
1778 if (!mTexStorage->isRenderTarget())
1779 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001780 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001781
Geoff Lang9e3f24f2014-08-27 12:06:04 -04001782 if (mRenderer->copyToRenderTarget3D(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001783 {
1784 delete newRenderTargetStorage;
1785 return gl::error(GL_OUT_OF_MEMORY, false);
1786 }
1787
1788 setCompleteTexStorage(newRenderTargetStorage);
1789 }
1790 }
1791
1792 return (mTexStorage && mTexStorage->isRenderTarget());
1793}
1794
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001795TextureStorage *TextureD3D_3D::getBaseLevelStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001796{
1797 return mTexStorage;
1798}
1799
1800const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1801{
1802 return mImageArray[0];
1803}
1804
1805bool TextureD3D_3D::isValidLevel(int level) const
1806{
1807 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1808}
1809
1810bool TextureD3D_3D::isLevelComplete(int level) const
1811{
1812 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1813
1814 if (isImmutable())
1815 {
1816 return true;
1817 }
1818
1819 GLsizei width = getBaseLevelWidth();
1820 GLsizei height = getBaseLevelHeight();
1821 GLsizei depth = getBaseLevelDepth();
1822
1823 if (width <= 0 || height <= 0 || depth <= 0)
1824 {
1825 return false;
1826 }
1827
1828 if (level == 0)
1829 {
1830 return true;
1831 }
1832
1833 ImageD3D *levelImage = mImageArray[level];
1834
1835 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1836 {
1837 return false;
1838 }
1839
1840 if (levelImage->getWidth() != std::max(1, width >> level))
1841 {
1842 return false;
1843 }
1844
1845 if (levelImage->getHeight() != std::max(1, height >> level))
1846 {
1847 return false;
1848 }
1849
1850 if (levelImage->getDepth() != std::max(1, depth >> level))
1851 {
1852 return false;
1853 }
1854
1855 return true;
1856}
1857
1858void TextureD3D_3D::updateStorageLevel(int level)
1859{
1860 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1861 ASSERT(isLevelComplete(level));
1862
1863 if (mImageArray[level]->isDirty())
1864 {
1865 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1866 }
1867}
1868
1869void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1870{
1871 // If there currently is a corresponding storage texture image, it has these parameters
1872 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1873 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1874 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1875 const GLenum storageFormat = getBaseLevelInternalFormat();
1876
1877 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1878
1879 if (mTexStorage)
1880 {
1881 const int storageLevels = mTexStorage->getLevelCount();
1882
1883 if ((level >= storageLevels && storageLevels != 0) ||
1884 width != storageWidth ||
1885 height != storageHeight ||
1886 depth != storageDepth ||
1887 internalformat != storageFormat) // Discard mismatched storage
1888 {
1889 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1890 {
1891 mImageArray[i]->markDirty();
1892 }
1893
1894 SafeDelete(mTexStorage);
1895 mDirtyImages = true;
1896 }
1897 }
1898}
1899
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001900gl::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 -07001901{
1902 if (isValidLevel(level))
1903 {
1904 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001905 gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
1906 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001907 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001908 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001909 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001910
1911 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001912 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001913
1914 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001915}
1916
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001917gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1918{
1919 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1920 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1921}
Brandon Jones142ec422014-07-16 10:31:30 -07001922
Jamie Madillcb83dc12014-09-29 10:46:12 -04001923gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1924{
1925 // The "layer" here does not apply to 3D images. We use one Image per mip.
1926 return gl::ImageIndex::Make3D(mip);
1927}
1928
Brandon Jones142ec422014-07-16 10:31:30 -07001929TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001930 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001931 mTexStorage(NULL)
1932{
1933 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1934 {
1935 mLayerCounts[level] = 0;
1936 mImageArray[level] = NULL;
1937 }
1938}
1939
1940TextureD3D_2DArray::~TextureD3D_2DArray()
1941{
Austin Kinross69822602014-08-12 15:51:37 -07001942 // Delete the Images before the TextureStorage.
1943 // Images might be relying on the TextureStorage for some of their data.
1944 // 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 -07001945 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001946 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001947}
1948
Brandon Jones142ec422014-07-16 10:31:30 -07001949Image *TextureD3D_2DArray::getImage(int level, int layer) const
1950{
1951 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1952 ASSERT(layer < mLayerCounts[level]);
1953 return mImageArray[level][layer];
1954}
1955
Jamie Madillfeda4d22014-09-17 13:03:29 -04001956Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1957{
1958 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1959 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1960 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1961 return mImageArray[index.mipIndex][index.layerIndex];
1962}
1963
Brandon Jones142ec422014-07-16 10:31:30 -07001964GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1965{
1966 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1967 return mLayerCounts[level];
1968}
1969
Brandon Jones142ec422014-07-16 10:31:30 -07001970GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1971{
1972 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1973}
1974
1975GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1976{
1977 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1978}
1979
1980GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1981{
1982 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1983}
1984
1985GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1986{
1987 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1988}
1989
1990bool TextureD3D_2DArray::isDepth(GLint level) const
1991{
Geoff Lang5d601382014-07-22 15:14:06 -04001992 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001993}
1994
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001995gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1996 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1997 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001998{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001999 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2000
Geoff Lang5d601382014-07-22 15:14:06 -04002001 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2002
Brandon Jones142ec422014-07-16 10:31:30 -07002003 redefineImage(level, sizedInternalFormat, width, height, depth);
2004
Geoff Lang5d601382014-07-22 15:14:06 -04002005 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2006 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002007
2008 for (int i = 0; i < depth; i++)
2009 {
2010 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002011 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2012 if (error.isError())
2013 {
2014 return error;
2015 }
Brandon Jones142ec422014-07-16 10:31:30 -07002016 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002017
2018 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002019}
2020
Geoff Langb5348332014-09-02 13:16:34 -04002021gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2022 GLsizei width, GLsizei height, GLsizei depth,
2023 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002024{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002025 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2026
Brandon Jones142ec422014-07-16 10:31:30 -07002027 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2028 redefineImage(level, format, width, height, depth);
2029
Geoff Lang5d601382014-07-22 15:14:06 -04002030 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2031 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002032
2033 for (int i = 0; i < depth; i++)
2034 {
2035 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002036 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2037 if (error.isError())
2038 {
2039 return error;
2040 }
Brandon Jones142ec422014-07-16 10:31:30 -07002041 }
Geoff Langb5348332014-09-02 13:16:34 -04002042
2043 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002044}
2045
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002046gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2047 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2048 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002049{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002050 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2051
Geoff Lang5d601382014-07-22 15:14:06 -04002052 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2053 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002054
2055 for (int i = 0; i < depth; i++)
2056 {
2057 int layer = zoffset + i;
2058 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2059
Jamie Madillfeda4d22014-09-17 13:03:29 -04002060 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002061 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2062 layerPixels, index);
2063 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002064 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002065 return error;
2066 }
2067
2068 error = commitRect(level, xoffset, yoffset, layer, width, height);
2069 if (error.isError())
2070 {
2071 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002072 }
2073 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002074
2075 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002076}
2077
Geoff Langb5348332014-09-02 13:16:34 -04002078gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2079 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2080 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002081{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002082 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2083
Geoff Lang5d601382014-07-22 15:14:06 -04002084 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2085 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002086
2087 for (int i = 0; i < depth; i++)
2088 {
2089 int layer = zoffset + i;
2090 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2091
Geoff Langb5348332014-09-02 13:16:34 -04002092 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2093 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002094 {
Geoff Langb5348332014-09-02 13:16:34 -04002095 return error;
2096 }
2097
2098 error = commitRect(level, xoffset, yoffset, layer, width, height);
2099 if (error.isError())
2100 {
2101 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002102 }
2103 }
Geoff Langb5348332014-09-02 13:16:34 -04002104
2105 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002106}
2107
Brandon Jonescef06ff2014-08-05 13:27:48 -07002108void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2109{
2110 UNIMPLEMENTED();
2111}
2112
Brandon Jones142ec422014-07-16 10:31:30 -07002113void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2114{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002115 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2116
Brandon Jones142ec422014-07-16 10:31:30 -07002117 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2118 // the current level we're copying to is defined (with appropriate format, width & height)
2119 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2120
2121 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2122 {
2123 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2124 mDirtyImages = true;
2125 }
2126 else
2127 {
2128 ensureRenderTarget();
2129
2130 if (isValidLevel(level))
2131 {
2132 updateStorageLevel(level);
2133
2134 gl::Rectangle sourceRect;
2135 sourceRect.x = x;
2136 sourceRect.width = width;
2137 sourceRect.y = y;
2138 sourceRect.height = height;
2139
Jamie Madill856d9d42014-09-18 15:08:49 -04002140 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2141 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002142 }
2143 }
2144}
2145
Brandon Jonescef06ff2014-08-05 13:27:48 -07002146void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002147{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002148 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2149
Brandon Jones142ec422014-07-16 10:31:30 -07002150 deleteImages();
2151
2152 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2153 {
2154 GLsizei levelWidth = std::max(1, width >> level);
2155 GLsizei levelHeight = std::max(1, height >> level);
2156
2157 mLayerCounts[level] = (level < levels ? depth : 0);
2158
2159 if (mLayerCounts[level] > 0)
2160 {
2161 // Create new images for this level
2162 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2163
2164 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2165 {
2166 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2167 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2168 levelHeight, 1, true);
2169 }
2170 }
2171 }
2172
2173 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002174
2175 bool renderTarget = IsRenderTargetUsage(mUsage);
2176 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002177 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002178}
2179
Brandon Jones6053a522014-07-25 16:22:09 -07002180void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002181{
Brandon Jones6053a522014-07-25 16:22:09 -07002182 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002183}
2184
Brandon Jones6053a522014-07-25 16:22:09 -07002185void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002186{
Brandon Jones6053a522014-07-25 16:22:09 -07002187 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002188}
2189
Brandon Jones6053a522014-07-25 16:22:09 -07002190
Jamie Madill4aa79e12014-09-29 10:46:14 -04002191void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002192{
2193 int baseWidth = getBaseLevelWidth();
2194 int baseHeight = getBaseLevelHeight();
2195 int baseDepth = getBaseLevelDepth();
2196 GLenum baseFormat = getBaseLevelInternalFormat();
2197
2198 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2199 int levelCount = mipLevels();
2200 for (int level = 1; level < levelCount; level++)
2201 {
2202 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2203 }
Brandon Jones142ec422014-07-16 10:31:30 -07002204}
2205
Jamie Madillac7579c2014-09-17 16:59:33 -04002206unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002207{
Jamie Madillc4833262014-09-18 16:18:26 -04002208 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002209}
2210
Jamie Madillac7579c2014-09-17 16:59:33 -04002211RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002212{
2213 // ensure the underlying texture is created
2214 if (!ensureRenderTarget())
2215 {
2216 return NULL;
2217 }
2218
Jamie Madillac7579c2014-09-17 16:59:33 -04002219 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002220 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002221}
2222
2223void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2224{
2225 // Only initialize the first time this texture is used as a render target or shader resource
2226 if (mTexStorage)
2227 {
2228 return;
2229 }
2230
2231 // do not attempt to create storage for nonexistant data
2232 if (!isLevelComplete(0))
2233 {
2234 return;
2235 }
2236
2237 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2238
2239 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2240 ASSERT(mTexStorage);
2241
2242 // flush image data to the storage
2243 updateStorage();
2244}
2245
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002246TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002247{
2248 GLsizei width = getBaseLevelWidth();
2249 GLsizei height = getBaseLevelHeight();
2250 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002251 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002252
2253 ASSERT(width > 0 && height > 0 && depth > 0);
2254
2255 // use existing storage level count, when previously specified by TexStorage*D
2256 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2257
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002258 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002259}
2260
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002261void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002262{
2263 SafeDelete(mTexStorage);
2264 mTexStorage = newCompleteTexStorage;
2265 mDirtyImages = true;
2266
2267 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2268 ASSERT(!mTexStorage->isManaged());
2269}
2270
2271void TextureD3D_2DArray::updateStorage()
2272{
2273 ASSERT(mTexStorage != NULL);
2274 GLint storageLevels = mTexStorage->getLevelCount();
2275 for (int level = 0; level < storageLevels; level++)
2276 {
2277 if (isLevelComplete(level))
2278 {
2279 updateStorageLevel(level);
2280 }
2281 }
2282}
2283
2284bool TextureD3D_2DArray::ensureRenderTarget()
2285{
2286 initializeStorage(true);
2287
2288 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2289 {
2290 ASSERT(mTexStorage);
2291 if (!mTexStorage->isRenderTarget())
2292 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002293 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002294
Geoff Lang9e3f24f2014-08-27 12:06:04 -04002295 if (mRenderer->copyToRenderTarget2DArray(newRenderTargetStorage, mTexStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002296 {
2297 delete newRenderTargetStorage;
2298 return gl::error(GL_OUT_OF_MEMORY, false);
2299 }
2300
2301 setCompleteTexStorage(newRenderTargetStorage);
2302 }
2303 }
2304
2305 return (mTexStorage && mTexStorage->isRenderTarget());
2306}
2307
2308const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2309{
2310 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2311}
2312
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002313TextureStorage *TextureD3D_2DArray::getBaseLevelStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002314{
2315 return mTexStorage;
2316}
2317
2318bool TextureD3D_2DArray::isValidLevel(int level) const
2319{
2320 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2321}
2322
2323bool TextureD3D_2DArray::isLevelComplete(int level) const
2324{
2325 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2326
2327 if (isImmutable())
2328 {
2329 return true;
2330 }
2331
2332 GLsizei width = getBaseLevelWidth();
2333 GLsizei height = getBaseLevelHeight();
2334 GLsizei layers = getLayers(0);
2335
2336 if (width <= 0 || height <= 0 || layers <= 0)
2337 {
2338 return false;
2339 }
2340
2341 if (level == 0)
2342 {
2343 return true;
2344 }
2345
2346 if (getInternalFormat(level) != getInternalFormat(0))
2347 {
2348 return false;
2349 }
2350
2351 if (getWidth(level) != std::max(1, width >> level))
2352 {
2353 return false;
2354 }
2355
2356 if (getHeight(level) != std::max(1, height >> level))
2357 {
2358 return false;
2359 }
2360
2361 if (getLayers(level) != layers)
2362 {
2363 return false;
2364 }
2365
2366 return true;
2367}
2368
2369void TextureD3D_2DArray::updateStorageLevel(int level)
2370{
2371 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2372 ASSERT(isLevelComplete(level));
2373
2374 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2375 {
2376 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2377 if (mImageArray[level][layer]->isDirty())
2378 {
2379 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2380 }
2381 }
2382}
2383
2384void TextureD3D_2DArray::deleteImages()
2385{
2386 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2387 {
2388 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2389 {
2390 delete mImageArray[level][layer];
2391 }
2392 delete[] mImageArray[level];
2393 mImageArray[level] = NULL;
2394 mLayerCounts[level] = 0;
2395 }
2396}
2397
2398void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2399{
2400 // If there currently is a corresponding storage texture image, it has these parameters
2401 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2402 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2403 const int storageDepth = getLayers(0);
2404 const GLenum storageFormat = getBaseLevelInternalFormat();
2405
2406 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2407 {
2408 delete mImageArray[level][layer];
2409 }
2410 delete[] mImageArray[level];
2411 mImageArray[level] = NULL;
2412 mLayerCounts[level] = depth;
2413
2414 if (depth > 0)
2415 {
2416 mImageArray[level] = new ImageD3D*[depth]();
2417
2418 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2419 {
2420 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2421 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2422 }
2423 }
2424
2425 if (mTexStorage)
2426 {
2427 const int storageLevels = mTexStorage->getLevelCount();
2428
2429 if ((level >= storageLevels && storageLevels != 0) ||
2430 width != storageWidth ||
2431 height != storageHeight ||
2432 depth != storageDepth ||
2433 internalformat != storageFormat) // Discard mismatched storage
2434 {
2435 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2436 {
2437 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2438 {
2439 mImageArray[level][layer]->markDirty();
2440 }
2441 }
2442
2443 delete mTexStorage;
2444 mTexStorage = NULL;
2445 mDirtyImages = true;
2446 }
2447 }
2448}
2449
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002450gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
Brandon Jones142ec422014-07-16 10:31:30 -07002451{
2452 if (isValidLevel(level) && layerTarget < getLayers(level))
2453 {
2454 ImageD3D *image = mImageArray[level][layerTarget];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002455 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
2456 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002457 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002458 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002459 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002460
2461 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002462 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002463
2464 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002465}
2466
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002467gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2468{
2469 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2470}
2471
Jamie Madillcb83dc12014-09-29 10:46:12 -04002472gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2473{
2474 return gl::ImageIndex::Make2DArray(mip, layer);
2475}
2476
Brandon Jones78b1acd2014-07-15 15:33:07 -07002477}