blob: 73237674290e12e68dfb65cc97aa1e917133c3dc [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),
Jamie Madill98553e32014-09-30 16:33:50 -040038 mImmutable(false),
39 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070040{
41}
42
43TextureD3D::~TextureD3D()
44{
45}
46
Brandon Jones6053a522014-07-25 16:22:09 -070047TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
48{
49 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
50 return static_cast<TextureD3D*>(texture);
51}
52
Jamie Madill2f06dbf2014-09-18 15:08:50 -040053TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070054{
55 // ensure the underlying texture is created
56 initializeStorage(false);
57
Jamie Madill98553e32014-09-30 16:33:50 -040058 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070059 {
60 updateStorage();
61 }
62
Jamie Madill98553e32014-09-30 16:33:50 -040063 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070064}
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 Madill98553e32014-09-30 16:33:50 -0400245TextureStorage *TextureD3D::getStorage()
246{
247 return mTexStorage;
248}
249
Jamie Madill4aa79e12014-09-29 10:46:14 -0400250void TextureD3D::generateMipmaps()
251{
252 // Set up proper image sizes.
253 initMipmapsImages();
254
255 // We know that all layers have the same dimension, for the texture to be complete
256 GLint layerCount = static_cast<GLint>(getLayerCount(0));
257 GLint mipCount = mipLevels();
258
259 // The following will create and initialize the storage, or update it if it exists
260 TextureStorage *storage = getNativeTexture();
261
262 bool renderableStorage = (storage && storage->isRenderTarget());
263
264 for (GLint layer = 0; layer < layerCount; ++layer)
265 {
266 for (GLint mip = 1; mip < mipCount; ++mip)
267 {
268 ASSERT(getLayerCount(mip) == layerCount);
269
270 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
271 gl::ImageIndex destIndex = getImageIndex(mip, layer);
272
273 if (renderableStorage)
274 {
275 // GPU-side mipmapping
276 storage->generateMipmap(sourceIndex, destIndex);
277 }
278 else
279 {
280 // CPU-side mipmapping
281 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
282 }
283 }
284 }
285}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700286
Jamie Madill135570a2014-09-30 16:33:51 -0400287bool TextureD3D::isBaseImageZeroSize() const
288{
289 Image *baseImage = getImage(getImageIndex(0, 0));
290
291 if (!baseImage || baseImage->getWidth() <= 0)
292 {
293 return true;
294 }
295
296 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
297 {
298 return true;
299 }
300
301 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
302 {
303 return true;
304 }
305
306 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
307 {
308 return true;
309 }
310
311 return false;
312}
313
314bool TextureD3D::ensureRenderTarget()
315{
316 initializeStorage(true);
317
318 if (!isBaseImageZeroSize())
319 {
320 ASSERT(mTexStorage);
321 if (!mTexStorage->isRenderTarget())
322 {
323 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
324
325 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
326 {
327 delete newRenderTargetStorage;
328 return gl::error(GL_OUT_OF_MEMORY, false);
329 }
330
331 setCompleteTexStorage(newRenderTargetStorage);
332 }
333 }
334
335 return (mTexStorage && mTexStorage->isRenderTarget());
336}
337
Brandon Jones78b1acd2014-07-15 15:33:07 -0700338TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400339 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700340{
341 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
342 {
343 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
344 }
345}
346
347TextureD3D_2D::~TextureD3D_2D()
348{
Austin Kinross69822602014-08-12 15:51:37 -0700349 // Delete the Images before the TextureStorage.
350 // Images might be relying on the TextureStorage for some of their data.
351 // 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 -0700352 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
353 {
354 delete mImageArray[i];
355 }
Austin Kinross69822602014-08-12 15:51:37 -0700356
357 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700358}
359
Brandon Jonescef06ff2014-08-05 13:27:48 -0700360Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700361{
362 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700363 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700364 return mImageArray[level];
365}
366
Jamie Madillfeda4d22014-09-17 13:03:29 -0400367Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
368{
369 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400370 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400371 ASSERT(index.type == GL_TEXTURE_2D);
372 return mImageArray[index.mipIndex];
373}
374
Brandon Jonescef06ff2014-08-05 13:27:48 -0700375GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700376{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700377 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
378 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700379}
380
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700381GLsizei TextureD3D_2D::getWidth(GLint level) const
382{
383 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
384 return mImageArray[level]->getWidth();
385 else
386 return 0;
387}
388
389GLsizei TextureD3D_2D::getHeight(GLint level) const
390{
391 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
392 return mImageArray[level]->getHeight();
393 else
394 return 0;
395}
396
397GLenum TextureD3D_2D::getInternalFormat(GLint level) const
398{
399 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
400 return mImageArray[level]->getInternalFormat();
401 else
402 return GL_NONE;
403}
404
405GLenum TextureD3D_2D::getActualFormat(GLint level) const
406{
407 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
408 return mImageArray[level]->getActualFormat();
409 else
410 return GL_NONE;
411}
412
413bool TextureD3D_2D::isDepth(GLint level) const
414{
Geoff Lang5d601382014-07-22 15:14:06 -0400415 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700416}
417
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400418gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
419 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
420 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700422 ASSERT(target == GL_TEXTURE_2D && depth == 1);
423
Geoff Lang5d601382014-07-22 15:14:06 -0400424 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
425
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700426 bool fastUnpacked = false;
427
Brandon Jonescef06ff2014-08-05 13:27:48 -0700428 redefineImage(level, sizedInternalFormat, width, height);
429
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700430 // Attempt a fast gpu copy of the pixel data to the surface
431 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
432 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400433 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
434
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400436 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700437 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
438
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400439 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400441 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
442 if (error.isError())
443 {
444 return error;
445 }
446
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700447 // Ensure we don't overwrite our newly initialized data
448 mImageArray[level]->markClean();
449
450 fastUnpacked = true;
451 }
452 }
453
454 if (!fastUnpacked)
455 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400456 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
457 if (error.isError())
458 {
459 return error;
460 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400462
463 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700464}
465
Geoff Langb5348332014-09-02 13:16:34 -0400466gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
467 GLsizei width, GLsizei height, GLsizei depth,
468 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700469{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700470 ASSERT(target == GL_TEXTURE_2D && depth == 1);
471
472 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
473 redefineImage(level, format, width, height);
474
Geoff Langb5348332014-09-02 13:16:34 -0400475 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700476}
477
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400478gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
479 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
480 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700482 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
483
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700484 bool fastUnpacked = false;
485
Jamie Madillac7579c2014-09-17 16:59:33 -0400486 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700487 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
488 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400489 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700490 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
491
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400492 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400494 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
495 if (error.isError())
496 {
497 return error;
498 }
499
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700500 // Ensure we don't overwrite our newly initialized data
501 mImageArray[level]->markClean();
502
503 fastUnpacked = true;
504 }
505 }
506
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400507 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700508 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400509 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
510 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
511 pixels, index);
512 if (error.isError())
513 {
514 return error;
515 }
516
517 error = commitRect(level, xoffset, yoffset, width, height);
518 if (error.isError())
519 {
520 return error;
521 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400523
524 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700525}
526
Geoff Langb5348332014-09-02 13:16:34 -0400527gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
528 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
529 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700530{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700531 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
532
Geoff Langb5348332014-09-02 13:16:34 -0400533 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
534 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535 {
Geoff Langb5348332014-09-02 13:16:34 -0400536 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700537 }
Geoff Langb5348332014-09-02 13:16:34 -0400538
539 error = commitRect(level, xoffset, yoffset, width, height);
540 if (error.isError())
541 {
542 return error;
543 }
544
545 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700546}
547
Brandon Jonescef06ff2014-08-05 13:27:48 -0700548void 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 -0700549{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700550 ASSERT(target == GL_TEXTURE_2D);
551
552 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
553 redefineImage(level, sizedInternalFormat, width, height);
554
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555 if (!mImageArray[level]->isRenderableFormat())
556 {
557 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
558 mDirtyImages = true;
559 }
560 else
561 {
562 ensureRenderTarget();
563 mImageArray[level]->markClean();
564
565 if (width != 0 && height != 0 && isValidLevel(level))
566 {
567 gl::Rectangle sourceRect;
568 sourceRect.x = x;
569 sourceRect.width = width;
570 sourceRect.y = y;
571 sourceRect.height = height;
572
Jamie Madill856d9d42014-09-18 15:08:49 -0400573 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700574 }
575 }
576}
577
578void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
579{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700580 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
581
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
583 // the current level we're copying to is defined (with appropriate format, width & height)
584 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
585
586 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
587 {
588 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
589 mDirtyImages = true;
590 }
591 else
592 {
593 ensureRenderTarget();
594
595 if (isValidLevel(level))
596 {
597 updateStorageLevel(level);
598
599 gl::Rectangle sourceRect;
600 sourceRect.x = x;
601 sourceRect.width = width;
602 sourceRect.y = y;
603 sourceRect.height = height;
604
Jamie Madill856d9d42014-09-18 15:08:49 -0400605 mRenderer->copyImage2D(source, sourceRect,
606 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
607 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608 }
609 }
610}
611
Brandon Jonescef06ff2014-08-05 13:27:48 -0700612void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700614 ASSERT(target == GL_TEXTURE_2D && depth == 1);
615
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 for (int level = 0; level < levels; level++)
617 {
618 GLsizei levelWidth = std::max(1, width >> level);
619 GLsizei levelHeight = std::max(1, height >> level);
620 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
621 }
622
623 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
624 {
625 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
626 }
627
628 mImmutable = true;
629
Jamie Madillc4833262014-09-18 16:18:26 -0400630 bool renderTarget = IsRenderTargetUsage(mUsage);
631 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400632 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700633}
634
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635void TextureD3D_2D::bindTexImage(egl::Surface *surface)
636{
637 GLenum internalformat = surface->getFormat();
638
639 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
640
641 if (mTexStorage)
642 {
643 SafeDelete(mTexStorage);
644 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400645
646 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700647
648 mDirtyImages = true;
649}
650
651void TextureD3D_2D::releaseTexImage()
652{
653 if (mTexStorage)
654 {
655 SafeDelete(mTexStorage);
656 }
657
658 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
659 {
660 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
661 }
662}
663
Jamie Madill4aa79e12014-09-29 10:46:14 -0400664void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700666 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700668 for (int level = 1; level < levelCount; level++)
669 {
670 redefineImage(level, getBaseLevelInternalFormat(),
671 std::max(getBaseLevelWidth() >> level, 1),
672 std::max(getBaseLevelHeight() >> level, 1));
673 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674}
675
Jamie Madillac7579c2014-09-17 16:59:33 -0400676unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677{
Jamie Madillac7579c2014-09-17 16:59:33 -0400678 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400679 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700680}
681
Jamie Madillac7579c2014-09-17 16:59:33 -0400682RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683{
Jamie Madillac7579c2014-09-17 16:59:33 -0400684 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700685
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 // ensure the underlying texture is created
687 if (!ensureRenderTarget())
688 {
689 return NULL;
690 }
691
Jamie Madillac7579c2014-09-17 16:59:33 -0400692 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400693 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694}
695
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700696bool TextureD3D_2D::isValidLevel(int level) const
697{
698 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
699}
700
701bool TextureD3D_2D::isLevelComplete(int level) const
702{
703 if (isImmutable())
704 {
705 return true;
706 }
707
Brandon Jones78b1acd2014-07-15 15:33:07 -0700708 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700709
710 GLsizei width = baseImage->getWidth();
711 GLsizei height = baseImage->getHeight();
712
713 if (width <= 0 || height <= 0)
714 {
715 return false;
716 }
717
718 // The base image level is complete if the width and height are positive
719 if (level == 0)
720 {
721 return true;
722 }
723
724 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700725 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700726
727 if (image->getInternalFormat() != baseImage->getInternalFormat())
728 {
729 return false;
730 }
731
732 if (image->getWidth() != std::max(1, width >> level))
733 {
734 return false;
735 }
736
737 if (image->getHeight() != std::max(1, height >> level))
738 {
739 return false;
740 }
741
742 return true;
743}
744
745// Constructs a native texture resource from the texture images
746void TextureD3D_2D::initializeStorage(bool renderTarget)
747{
748 // Only initialize the first time this texture is used as a render target or shader resource
749 if (mTexStorage)
750 {
751 return;
752 }
753
754 // do not attempt to create storage for nonexistant data
755 if (!isLevelComplete(0))
756 {
757 return;
758 }
759
760 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
761
762 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
763 ASSERT(mTexStorage);
764
765 // flush image data to the storage
766 updateStorage();
767}
768
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400769TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770{
771 GLsizei width = getBaseLevelWidth();
772 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400773 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700774
775 ASSERT(width > 0 && height > 0);
776
777 // use existing storage level count, when previously specified by TexStorage*D
778 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
779
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400780 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700781}
782
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400783void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700784{
785 SafeDelete(mTexStorage);
786 mTexStorage = newCompleteTexStorage;
787
788 if (mTexStorage && mTexStorage->isManaged())
789 {
790 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
791 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400792 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793 }
794 }
795
796 mDirtyImages = true;
797}
798
799void TextureD3D_2D::updateStorage()
800{
801 ASSERT(mTexStorage != NULL);
802 GLint storageLevels = mTexStorage->getLevelCount();
803 for (int level = 0; level < storageLevels; level++)
804 {
805 if (mImageArray[level]->isDirty() && isLevelComplete(level))
806 {
807 updateStorageLevel(level);
808 }
809 }
810}
811
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
813{
814 return mImageArray[0];
815}
816
817void TextureD3D_2D::updateStorageLevel(int level)
818{
819 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
820 ASSERT(isLevelComplete(level));
821
822 if (mImageArray[level]->isDirty())
823 {
824 commitRect(level, 0, 0, getWidth(level), getHeight(level));
825 }
826}
827
828void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
829{
830 // If there currently is a corresponding storage texture image, it has these parameters
831 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
832 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
833 const GLenum storageFormat = getBaseLevelInternalFormat();
834
835 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
836
837 if (mTexStorage)
838 {
839 const int storageLevels = mTexStorage->getLevelCount();
840
841 if ((level >= storageLevels && storageLevels != 0) ||
842 width != storageWidth ||
843 height != storageHeight ||
844 internalformat != storageFormat) // Discard mismatched storage
845 {
846 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
847 {
848 mImageArray[i]->markDirty();
849 }
850
851 SafeDelete(mTexStorage);
852 mDirtyImages = true;
853 }
854 }
855}
856
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400857gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700858{
859 if (isValidLevel(level))
860 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700861 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400862 gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
863 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400865 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400867
868 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400870
871 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700872}
873
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400874gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
875{
876 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
877}
Brandon Jones0511e802014-07-14 16:27:26 -0700878
Jamie Madillcb83dc12014-09-29 10:46:12 -0400879gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
880{
881 // "layer" does not apply to 2D Textures.
882 return gl::ImageIndex::Make2D(mip);
883}
884
Brandon Jones78b1acd2014-07-15 15:33:07 -0700885TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400886 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700887{
888 for (int i = 0; i < 6; i++)
889 {
890 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
891 {
892 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
893 }
894 }
895}
896
897TextureD3D_Cube::~TextureD3D_Cube()
898{
Austin Kinross69822602014-08-12 15:51:37 -0700899 // Delete the Images before the TextureStorage.
900 // Images might be relying on the TextureStorage for some of their data.
901 // 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 -0700902 for (int i = 0; i < 6; i++)
903 {
904 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
905 {
906 SafeDelete(mImageArray[i][j]);
907 }
908 }
Austin Kinross69822602014-08-12 15:51:37 -0700909
910 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700911}
912
Brandon Jonescef06ff2014-08-05 13:27:48 -0700913Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700914{
915 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916 ASSERT(layer < 6);
917 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700918}
919
Jamie Madillfeda4d22014-09-17 13:03:29 -0400920Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
921{
922 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
923 ASSERT(index.layerIndex < 6);
924 return mImageArray[index.layerIndex][index.mipIndex];
925}
926
Brandon Jonescef06ff2014-08-05 13:27:48 -0700927GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700928{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700929 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
930 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700931}
932
Brandon Jonescef06ff2014-08-05 13:27:48 -0700933GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700934{
935 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700936 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700937 else
938 return GL_NONE;
939}
940
Brandon Jonescef06ff2014-08-05 13:27:48 -0700941bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700942{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700943 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700944}
945
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400946gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
947 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
948 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700949{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700950 ASSERT(depth == 1);
951
952 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400953 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700954
955 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
956
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400957 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700958}
959
Geoff Langb5348332014-09-02 13:16:34 -0400960gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
961 GLsizei width, GLsizei height, GLsizei depth,
962 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700963{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700964 ASSERT(depth == 1);
965
Brandon Jones0511e802014-07-14 16:27:26 -0700966 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700967 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
968
Brandon Jones0511e802014-07-14 16:27:26 -0700969 redefineImage(faceIndex, level, format, width, height);
970
Geoff Langb5348332014-09-02 13:16:34 -0400971 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700972}
973
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400974gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
975 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
976 const gl::PixelUnpackState &unpack, 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
Jamie Madillfeda4d22014-09-17 13:03:29 -0400982 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400983 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
984 index);
985 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700986 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400987 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700988 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400989
990 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
991 if (error.isError())
992 {
993 return error;
994 }
995
996 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700997}
998
Geoff Langb5348332014-09-02 13:16:34 -0400999gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1000 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1001 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001002{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001003 ASSERT(depth == 1 && zoffset == 0);
1004
1005 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1006
Geoff Langb5348332014-09-02 13:16:34 -04001007 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]);
1008 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001009 {
Geoff Langb5348332014-09-02 13:16:34 -04001010 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001011 }
Geoff Langb5348332014-09-02 13:16:34 -04001012
1013 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
1014 if (error.isError())
1015 {
1016 return error;
1017 }
1018
1019 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001020}
1021
1022void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1023{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001024 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001025 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1026
Brandon Jones0511e802014-07-14 16:27:26 -07001027 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1028
1029 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1030 {
1031 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1032 mDirtyImages = true;
1033 }
1034 else
1035 {
1036 ensureRenderTarget();
1037 mImageArray[faceIndex][level]->markClean();
1038
1039 ASSERT(width == height);
1040
1041 if (width > 0 && isValidFaceLevel(faceIndex, level))
1042 {
1043 gl::Rectangle sourceRect;
1044 sourceRect.x = x;
1045 sourceRect.width = width;
1046 sourceRect.y = y;
1047 sourceRect.height = height;
1048
Jamie Madill856d9d42014-09-18 15:08:49 -04001049 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001050 }
1051 }
1052}
1053
1054void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1055{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001056 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001057
1058 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1059 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1060 // rely on the "getBaseLevel*" methods reliably otherwise.
1061 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1062
1063 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1064 {
1065 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1066 mDirtyImages = true;
1067 }
1068 else
1069 {
1070 ensureRenderTarget();
1071
1072 if (isValidFaceLevel(faceIndex, level))
1073 {
1074 updateStorageFaceLevel(faceIndex, level);
1075
1076 gl::Rectangle sourceRect;
1077 sourceRect.x = x;
1078 sourceRect.width = width;
1079 sourceRect.y = y;
1080 sourceRect.height = height;
1081
Jamie Madill856d9d42014-09-18 15:08:49 -04001082 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1083 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001084 }
1085 }
1086}
1087
Brandon Jonescef06ff2014-08-05 13:27:48 -07001088void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001089{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001090 ASSERT(width == height);
1091 ASSERT(depth == 1);
1092
Brandon Jones0511e802014-07-14 16:27:26 -07001093 for (int level = 0; level < levels; level++)
1094 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001095 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001096 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1097 {
1098 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1099 }
1100 }
1101
1102 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1103 {
1104 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1105 {
1106 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1107 }
1108 }
1109
1110 mImmutable = true;
1111
Jamie Madillc4833262014-09-18 16:18:26 -04001112 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001113 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1114 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001115}
1116
Brandon Jones0511e802014-07-14 16:27:26 -07001117// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1118bool TextureD3D_Cube::isCubeComplete() const
1119{
1120 int baseWidth = getBaseLevelWidth();
1121 int baseHeight = getBaseLevelHeight();
1122 GLenum baseFormat = getBaseLevelInternalFormat();
1123
1124 if (baseWidth <= 0 || baseWidth != baseHeight)
1125 {
1126 return false;
1127 }
1128
1129 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1130 {
1131 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1132
1133 if (faceBaseImage.getWidth() != baseWidth ||
1134 faceBaseImage.getHeight() != baseHeight ||
1135 faceBaseImage.getInternalFormat() != baseFormat )
1136 {
1137 return false;
1138 }
1139 }
1140
1141 return true;
1142}
1143
Brandon Jones6053a522014-07-25 16:22:09 -07001144void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1145{
1146 UNREACHABLE();
1147}
1148
1149void TextureD3D_Cube::releaseTexImage()
1150{
1151 UNREACHABLE();
1152}
1153
1154
Jamie Madill4aa79e12014-09-29 10:46:14 -04001155void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001156{
1157 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1158 int levelCount = mipLevels();
1159 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1160 {
1161 for (int level = 1; level < levelCount; level++)
1162 {
1163 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1164 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1165 }
1166 }
Brandon Jones0511e802014-07-14 16:27:26 -07001167}
1168
Jamie Madillac7579c2014-09-17 16:59:33 -04001169unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
Jamie Madillc4833262014-09-18 16:18:26 -04001171 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001172}
1173
Jamie Madillac7579c2014-09-17 16:59:33 -04001174RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001175{
Jamie Madillac7579c2014-09-17 16:59:33 -04001176 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001177
1178 // ensure the underlying texture is created
1179 if (!ensureRenderTarget())
1180 {
1181 return NULL;
1182 }
1183
Jamie Madillac7579c2014-09-17 16:59:33 -04001184 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001185 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001186}
1187
Brandon Jones0511e802014-07-14 16:27:26 -07001188void TextureD3D_Cube::initializeStorage(bool renderTarget)
1189{
1190 // Only initialize the first time this texture is used as a render target or shader resource
1191 if (mTexStorage)
1192 {
1193 return;
1194 }
1195
1196 // do not attempt to create storage for nonexistant data
1197 if (!isFaceLevelComplete(0, 0))
1198 {
1199 return;
1200 }
1201
1202 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1203
1204 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1205 ASSERT(mTexStorage);
1206
1207 // flush image data to the storage
1208 updateStorage();
1209}
1210
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001211TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001212{
1213 GLsizei size = getBaseLevelWidth();
1214
1215 ASSERT(size > 0);
1216
1217 // use existing storage level count, when previously specified by TexStorage*D
1218 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1219
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001220 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001221}
1222
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001223void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001224{
1225 SafeDelete(mTexStorage);
1226 mTexStorage = newCompleteTexStorage;
1227
1228 if (mTexStorage && mTexStorage->isManaged())
1229 {
1230 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1231 {
1232 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1233 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001234 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001235 }
1236 }
1237 }
1238
1239 mDirtyImages = true;
1240}
1241
1242void TextureD3D_Cube::updateStorage()
1243{
1244 ASSERT(mTexStorage != NULL);
1245 GLint storageLevels = mTexStorage->getLevelCount();
1246 for (int face = 0; face < 6; face++)
1247 {
1248 for (int level = 0; level < storageLevels; level++)
1249 {
1250 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1251 {
1252 updateStorageFaceLevel(face, level);
1253 }
1254 }
1255 }
1256}
1257
Brandon Jones0511e802014-07-14 16:27:26 -07001258const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1259{
1260 // Note: if we are not cube-complete, there is no single base level image that can describe all
1261 // cube faces, so this method is only well-defined for a cube-complete base level.
1262 return mImageArray[0][0];
1263}
1264
Brandon Jones0511e802014-07-14 16:27:26 -07001265bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1266{
1267 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1268}
1269
Brandon Jones0511e802014-07-14 16:27:26 -07001270bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1271{
1272 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1273
1274 if (isImmutable())
1275 {
1276 return true;
1277 }
1278
1279 int baseSize = getBaseLevelWidth();
1280
1281 if (baseSize <= 0)
1282 {
1283 return false;
1284 }
1285
1286 // "isCubeComplete" checks for base level completeness and we must call that
1287 // to determine if any face at level 0 is complete. We omit that check here
1288 // to avoid re-checking cube-completeness for every face at level 0.
1289 if (level == 0)
1290 {
1291 return true;
1292 }
1293
1294 // Check that non-zero levels are consistent with the base level.
1295 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1296
1297 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1298 {
1299 return false;
1300 }
1301
1302 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1303 {
1304 return false;
1305 }
1306
1307 return true;
1308}
1309
1310void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1311{
1312 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1313 ImageD3D *image = mImageArray[faceIndex][level];
1314
1315 if (image->isDirty())
1316 {
1317 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1318 }
1319}
1320
1321void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1322{
1323 // If there currently is a corresponding storage texture image, it has these parameters
1324 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1325 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1326 const GLenum storageFormat = getBaseLevelInternalFormat();
1327
1328 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1329
1330 if (mTexStorage)
1331 {
1332 const int storageLevels = mTexStorage->getLevelCount();
1333
1334 if ((level >= storageLevels && storageLevels != 0) ||
1335 width != storageWidth ||
1336 height != storageHeight ||
1337 internalformat != storageFormat) // Discard mismatched storage
1338 {
1339 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1340 {
1341 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1342 {
1343 mImageArray[faceIndex][level]->markDirty();
1344 }
1345 }
1346
1347 SafeDelete(mTexStorage);
1348
1349 mDirtyImages = true;
1350 }
1351 }
1352}
1353
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001354gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jones0511e802014-07-14 16:27:26 -07001355{
1356 if (isValidFaceLevel(faceIndex, level))
1357 {
1358 ImageD3D *image = mImageArray[faceIndex][level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001359 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
1360 if (error.isError())
1361 {
1362 return error;
1363 }
1364
1365 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001366 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001367
1368 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001369}
1370
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001371gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1372{
1373 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1374}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001375
Jamie Madillcb83dc12014-09-29 10:46:12 -04001376gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1377{
1378 // The "layer" of the image index corresponds to the cube face
1379 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1380}
1381
Brandon Jones78b1acd2014-07-15 15:33:07 -07001382TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001383 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001384{
1385 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1386 {
1387 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1388 }
1389}
1390
1391TextureD3D_3D::~TextureD3D_3D()
1392{
Austin Kinross69822602014-08-12 15:51:37 -07001393 // Delete the Images before the TextureStorage.
1394 // Images might be relying on the TextureStorage for some of their data.
1395 // 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 -07001396 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1397 {
1398 delete mImageArray[i];
1399 }
Austin Kinross69822602014-08-12 15:51:37 -07001400
1401 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001402}
1403
Brandon Jonescef06ff2014-08-05 13:27:48 -07001404Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001405{
1406 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001407 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001408 return mImageArray[level];
1409}
1410
Jamie Madillfeda4d22014-09-17 13:03:29 -04001411Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1412{
1413 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001414 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001415 ASSERT(index.type == GL_TEXTURE_3D);
1416 return mImageArray[index.mipIndex];
1417}
1418
Brandon Jonescef06ff2014-08-05 13:27:48 -07001419GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001420{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001421 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1422 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001423}
1424
Brandon Jones78b1acd2014-07-15 15:33:07 -07001425GLsizei TextureD3D_3D::getWidth(GLint level) const
1426{
1427 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1428 return mImageArray[level]->getWidth();
1429 else
1430 return 0;
1431}
1432
1433GLsizei TextureD3D_3D::getHeight(GLint level) const
1434{
1435 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1436 return mImageArray[level]->getHeight();
1437 else
1438 return 0;
1439}
1440
1441GLsizei TextureD3D_3D::getDepth(GLint level) const
1442{
1443 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1444 return mImageArray[level]->getDepth();
1445 else
1446 return 0;
1447}
1448
1449GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1450{
1451 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1452 return mImageArray[level]->getInternalFormat();
1453 else
1454 return GL_NONE;
1455}
1456
1457bool TextureD3D_3D::isDepth(GLint level) const
1458{
Geoff Lang5d601382014-07-22 15:14:06 -04001459 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001460}
1461
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001462gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1463 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1464 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001465{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001466 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001467 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1468
Brandon Jones78b1acd2014-07-15 15:33:07 -07001469 redefineImage(level, sizedInternalFormat, width, height, depth);
1470
1471 bool fastUnpacked = false;
1472
1473 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1474 if (isFastUnpackable(unpack, sizedInternalFormat))
1475 {
1476 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001477 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1478 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1480
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001481 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001482 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001483 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1484 if (error.isError())
1485 {
1486 return error;
1487 }
1488
Brandon Jones78b1acd2014-07-15 15:33:07 -07001489 // Ensure we don't overwrite our newly initialized data
1490 mImageArray[level]->markClean();
1491
1492 fastUnpacked = true;
1493 }
1494 }
1495
1496 if (!fastUnpacked)
1497 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001498 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1499 if (error.isError())
1500 {
1501 return error;
1502 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001504
1505 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001506}
1507
Geoff Langb5348332014-09-02 13:16:34 -04001508gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1509 GLsizei width, GLsizei height,GLsizei depth,
1510 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001512 ASSERT(target == GL_TEXTURE_3D);
1513
Brandon Jones78b1acd2014-07-15 15:33:07 -07001514 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1515 redefineImage(level, format, width, height, depth);
1516
Geoff Langb5348332014-09-02 13:16:34 -04001517 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001518}
1519
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001520gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1521 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1522 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001524 ASSERT(target == GL_TEXTURE_3D);
1525
Brandon Jones78b1acd2014-07-15 15:33:07 -07001526 bool fastUnpacked = false;
1527
Jamie Madillac7579c2014-09-17 16:59:33 -04001528 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1529
Brandon Jones78b1acd2014-07-15 15:33:07 -07001530 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1531 if (isFastUnpackable(unpack, getInternalFormat(level)))
1532 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001533 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001534 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1535
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001536 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001537 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001538 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1539 if (error.isError())
1540 {
1541 return error;
1542 }
1543
Brandon Jones78b1acd2014-07-15 15:33:07 -07001544 // Ensure we don't overwrite our newly initialized data
1545 mImageArray[level]->markClean();
1546
1547 fastUnpacked = true;
1548 }
1549 }
1550
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001551 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001552 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001553 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1554 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1555 pixels, index);
1556 if (error.isError())
1557 {
1558 return error;
1559 }
1560
1561 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1562 if (error.isError())
1563 {
1564 return error;
1565 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001566 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001567
1568 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001569}
1570
Geoff Langb5348332014-09-02 13:16:34 -04001571gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1572 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1573 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001574{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001575 ASSERT(target == GL_TEXTURE_3D);
1576
Geoff Langb5348332014-09-02 13:16:34 -04001577 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1578 format, imageSize, pixels, mImageArray[level]);
1579 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001580 {
Geoff Langb5348332014-09-02 13:16:34 -04001581 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001582 }
Geoff Langb5348332014-09-02 13:16:34 -04001583
1584 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1585 if (error.isError())
1586 {
1587 return error;
1588 }
1589
1590 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001591}
1592
Brandon Jonescef06ff2014-08-05 13:27:48 -07001593void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1594{
1595 UNIMPLEMENTED();
1596}
1597
Brandon Jones78b1acd2014-07-15 15:33:07 -07001598void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1599{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001600 ASSERT(target == GL_TEXTURE_3D);
1601
Brandon Jones78b1acd2014-07-15 15:33:07 -07001602 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1603 // the current level we're copying to is defined (with appropriate format, width & height)
1604 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1605
1606 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1607 {
1608 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1609 mDirtyImages = true;
1610 }
1611 else
1612 {
1613 ensureRenderTarget();
1614
1615 if (isValidLevel(level))
1616 {
1617 updateStorageLevel(level);
1618
1619 gl::Rectangle sourceRect;
1620 sourceRect.x = x;
1621 sourceRect.width = width;
1622 sourceRect.y = y;
1623 sourceRect.height = height;
1624
Jamie Madill856d9d42014-09-18 15:08:49 -04001625 mRenderer->copyImage3D(source, sourceRect,
1626 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1627 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001628 }
1629 }
1630}
1631
Brandon Jonescef06ff2014-08-05 13:27:48 -07001632void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001633{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001634 ASSERT(target == GL_TEXTURE_3D);
1635
Brandon Jones78b1acd2014-07-15 15:33:07 -07001636 for (int level = 0; level < levels; level++)
1637 {
1638 GLsizei levelWidth = std::max(1, width >> level);
1639 GLsizei levelHeight = std::max(1, height >> level);
1640 GLsizei levelDepth = std::max(1, depth >> level);
1641 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1642 }
1643
1644 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1645 {
1646 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1647 }
1648
1649 mImmutable = true;
1650
Jamie Madillc4833262014-09-18 16:18:26 -04001651 bool renderTarget = IsRenderTargetUsage(mUsage);
1652 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001653 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654}
1655
Brandon Jones6053a522014-07-25 16:22:09 -07001656void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657{
Brandon Jones6053a522014-07-25 16:22:09 -07001658 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001659}
1660
Brandon Jones6053a522014-07-25 16:22:09 -07001661void TextureD3D_3D::releaseTexImage()
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 -07001666
Jamie Madill4aa79e12014-09-29 10:46:14 -04001667void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001668{
1669 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1670 int levelCount = mipLevels();
1671 for (int level = 1; level < levelCount; level++)
1672 {
1673 redefineImage(level, getBaseLevelInternalFormat(),
1674 std::max(getBaseLevelWidth() >> level, 1),
1675 std::max(getBaseLevelHeight() >> level, 1),
1676 std::max(getBaseLevelDepth() >> level, 1));
1677 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001678}
1679
Jamie Madillac7579c2014-09-17 16:59:33 -04001680unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001681{
Jamie Madillc4833262014-09-18 16:18:26 -04001682 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683}
1684
Jamie Madillac7579c2014-09-17 16:59:33 -04001685RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001686{
1687 // ensure the underlying texture is created
1688 if (!ensureRenderTarget())
1689 {
1690 return NULL;
1691 }
1692
Jamie Madillac7579c2014-09-17 16:59:33 -04001693 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001694 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001695 updateStorage();
1696 }
1697 else
1698 {
1699 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001700 }
1701
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001702 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001703}
1704
1705void TextureD3D_3D::initializeStorage(bool renderTarget)
1706{
1707 // Only initialize the first time this texture is used as a render target or shader resource
1708 if (mTexStorage)
1709 {
1710 return;
1711 }
1712
1713 // do not attempt to create storage for nonexistant data
1714 if (!isLevelComplete(0))
1715 {
1716 return;
1717 }
1718
1719 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1720
1721 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1722 ASSERT(mTexStorage);
1723
1724 // flush image data to the storage
1725 updateStorage();
1726}
1727
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001728TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001729{
1730 GLsizei width = getBaseLevelWidth();
1731 GLsizei height = getBaseLevelHeight();
1732 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001733 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001734
1735 ASSERT(width > 0 && height > 0 && depth > 0);
1736
1737 // use existing storage level count, when previously specified by TexStorage*D
1738 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1739
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001740 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741}
1742
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001743void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001744{
1745 SafeDelete(mTexStorage);
1746 mTexStorage = newCompleteTexStorage;
1747 mDirtyImages = true;
1748
1749 // We do not support managed 3D storage, as that is D3D9/ES2-only
1750 ASSERT(!mTexStorage->isManaged());
1751}
1752
1753void TextureD3D_3D::updateStorage()
1754{
1755 ASSERT(mTexStorage != NULL);
1756 GLint storageLevels = mTexStorage->getLevelCount();
1757 for (int level = 0; level < storageLevels; level++)
1758 {
1759 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1760 {
1761 updateStorageLevel(level);
1762 }
1763 }
1764}
1765
Brandon Jones78b1acd2014-07-15 15:33:07 -07001766const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1767{
1768 return mImageArray[0];
1769}
1770
1771bool TextureD3D_3D::isValidLevel(int level) const
1772{
1773 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1774}
1775
1776bool TextureD3D_3D::isLevelComplete(int level) const
1777{
1778 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1779
1780 if (isImmutable())
1781 {
1782 return true;
1783 }
1784
1785 GLsizei width = getBaseLevelWidth();
1786 GLsizei height = getBaseLevelHeight();
1787 GLsizei depth = getBaseLevelDepth();
1788
1789 if (width <= 0 || height <= 0 || depth <= 0)
1790 {
1791 return false;
1792 }
1793
1794 if (level == 0)
1795 {
1796 return true;
1797 }
1798
1799 ImageD3D *levelImage = mImageArray[level];
1800
1801 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1802 {
1803 return false;
1804 }
1805
1806 if (levelImage->getWidth() != std::max(1, width >> level))
1807 {
1808 return false;
1809 }
1810
1811 if (levelImage->getHeight() != std::max(1, height >> level))
1812 {
1813 return false;
1814 }
1815
1816 if (levelImage->getDepth() != std::max(1, depth >> level))
1817 {
1818 return false;
1819 }
1820
1821 return true;
1822}
1823
1824void TextureD3D_3D::updateStorageLevel(int level)
1825{
1826 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1827 ASSERT(isLevelComplete(level));
1828
1829 if (mImageArray[level]->isDirty())
1830 {
1831 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1832 }
1833}
1834
1835void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1836{
1837 // If there currently is a corresponding storage texture image, it has these parameters
1838 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1839 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1840 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1841 const GLenum storageFormat = getBaseLevelInternalFormat();
1842
1843 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1844
1845 if (mTexStorage)
1846 {
1847 const int storageLevels = mTexStorage->getLevelCount();
1848
1849 if ((level >= storageLevels && storageLevels != 0) ||
1850 width != storageWidth ||
1851 height != storageHeight ||
1852 depth != storageDepth ||
1853 internalformat != storageFormat) // Discard mismatched storage
1854 {
1855 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1856 {
1857 mImageArray[i]->markDirty();
1858 }
1859
1860 SafeDelete(mTexStorage);
1861 mDirtyImages = true;
1862 }
1863 }
1864}
1865
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001866gl::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 -07001867{
1868 if (isValidLevel(level))
1869 {
1870 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001871 gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
1872 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001873 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001874 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001875 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001876
1877 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001878 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001879
1880 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001881}
1882
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001883gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1884{
1885 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1886 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1887}
Brandon Jones142ec422014-07-16 10:31:30 -07001888
Jamie Madillcb83dc12014-09-29 10:46:12 -04001889gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1890{
1891 // The "layer" here does not apply to 3D images. We use one Image per mip.
1892 return gl::ImageIndex::Make3D(mip);
1893}
1894
Brandon Jones142ec422014-07-16 10:31:30 -07001895TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001896 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001897{
1898 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1899 {
1900 mLayerCounts[level] = 0;
1901 mImageArray[level] = NULL;
1902 }
1903}
1904
1905TextureD3D_2DArray::~TextureD3D_2DArray()
1906{
Austin Kinross69822602014-08-12 15:51:37 -07001907 // Delete the Images before the TextureStorage.
1908 // Images might be relying on the TextureStorage for some of their data.
1909 // 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 -07001910 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001911 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001912}
1913
Brandon Jones142ec422014-07-16 10:31:30 -07001914Image *TextureD3D_2DArray::getImage(int level, int layer) const
1915{
1916 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1917 ASSERT(layer < mLayerCounts[level]);
1918 return mImageArray[level][layer];
1919}
1920
Jamie Madillfeda4d22014-09-17 13:03:29 -04001921Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1922{
1923 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1924 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1925 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1926 return mImageArray[index.mipIndex][index.layerIndex];
1927}
1928
Brandon Jones142ec422014-07-16 10:31:30 -07001929GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1930{
1931 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1932 return mLayerCounts[level];
1933}
1934
Brandon Jones142ec422014-07-16 10:31:30 -07001935GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1936{
1937 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1938}
1939
1940GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1941{
1942 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1943}
1944
1945GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1946{
1947 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1948}
1949
1950GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1951{
1952 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1953}
1954
1955bool TextureD3D_2DArray::isDepth(GLint level) const
1956{
Geoff Lang5d601382014-07-22 15:14:06 -04001957 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001958}
1959
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001960gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1961 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1962 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001963{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001964 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1965
Geoff Lang5d601382014-07-22 15:14:06 -04001966 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1967
Brandon Jones142ec422014-07-16 10:31:30 -07001968 redefineImage(level, sizedInternalFormat, width, height, depth);
1969
Geoff Lang5d601382014-07-22 15:14:06 -04001970 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1971 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001972
1973 for (int i = 0; i < depth; i++)
1974 {
1975 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001976 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1977 if (error.isError())
1978 {
1979 return error;
1980 }
Brandon Jones142ec422014-07-16 10:31:30 -07001981 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001982
1983 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001984}
1985
Geoff Langb5348332014-09-02 13:16:34 -04001986gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1987 GLsizei width, GLsizei height, GLsizei depth,
1988 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001989{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001990 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1991
Brandon Jones142ec422014-07-16 10:31:30 -07001992 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1993 redefineImage(level, format, width, height, depth);
1994
Geoff Lang5d601382014-07-22 15:14:06 -04001995 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1996 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001997
1998 for (int i = 0; i < depth; i++)
1999 {
2000 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002001 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2002 if (error.isError())
2003 {
2004 return error;
2005 }
Brandon Jones142ec422014-07-16 10:31:30 -07002006 }
Geoff Langb5348332014-09-02 13:16:34 -04002007
2008 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002009}
2010
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002011gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2012 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2013 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002014{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002015 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2016
Geoff Lang5d601382014-07-22 15:14:06 -04002017 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2018 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002019
2020 for (int i = 0; i < depth; i++)
2021 {
2022 int layer = zoffset + i;
2023 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2024
Jamie Madillfeda4d22014-09-17 13:03:29 -04002025 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002026 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2027 layerPixels, index);
2028 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002029 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002030 return error;
2031 }
2032
2033 error = commitRect(level, xoffset, yoffset, layer, width, height);
2034 if (error.isError())
2035 {
2036 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002037 }
2038 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002039
2040 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002041}
2042
Geoff Langb5348332014-09-02 13:16:34 -04002043gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2044 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2045 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002046{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002047 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2048
Geoff Lang5d601382014-07-22 15:14:06 -04002049 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2050 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002051
2052 for (int i = 0; i < depth; i++)
2053 {
2054 int layer = zoffset + i;
2055 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2056
Geoff Langb5348332014-09-02 13:16:34 -04002057 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2058 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002059 {
Geoff Langb5348332014-09-02 13:16:34 -04002060 return error;
2061 }
2062
2063 error = commitRect(level, xoffset, yoffset, layer, width, height);
2064 if (error.isError())
2065 {
2066 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002067 }
2068 }
Geoff Langb5348332014-09-02 13:16:34 -04002069
2070 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002071}
2072
Brandon Jonescef06ff2014-08-05 13:27:48 -07002073void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2074{
2075 UNIMPLEMENTED();
2076}
2077
Brandon Jones142ec422014-07-16 10:31:30 -07002078void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2079{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002080 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2081
Brandon Jones142ec422014-07-16 10:31:30 -07002082 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2083 // the current level we're copying to is defined (with appropriate format, width & height)
2084 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2085
2086 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2087 {
2088 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2089 mDirtyImages = true;
2090 }
2091 else
2092 {
2093 ensureRenderTarget();
2094
2095 if (isValidLevel(level))
2096 {
2097 updateStorageLevel(level);
2098
2099 gl::Rectangle sourceRect;
2100 sourceRect.x = x;
2101 sourceRect.width = width;
2102 sourceRect.y = y;
2103 sourceRect.height = height;
2104
Jamie Madill856d9d42014-09-18 15:08:49 -04002105 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2106 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002107 }
2108 }
2109}
2110
Brandon Jonescef06ff2014-08-05 13:27:48 -07002111void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002112{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002113 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2114
Brandon Jones142ec422014-07-16 10:31:30 -07002115 deleteImages();
2116
2117 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2118 {
2119 GLsizei levelWidth = std::max(1, width >> level);
2120 GLsizei levelHeight = std::max(1, height >> level);
2121
2122 mLayerCounts[level] = (level < levels ? depth : 0);
2123
2124 if (mLayerCounts[level] > 0)
2125 {
2126 // Create new images for this level
2127 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2128
2129 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2130 {
2131 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2132 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2133 levelHeight, 1, true);
2134 }
2135 }
2136 }
2137
2138 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002139
2140 bool renderTarget = IsRenderTargetUsage(mUsage);
2141 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002142 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002143}
2144
Brandon Jones6053a522014-07-25 16:22:09 -07002145void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002146{
Brandon Jones6053a522014-07-25 16:22:09 -07002147 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002148}
2149
Brandon Jones6053a522014-07-25 16:22:09 -07002150void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002151{
Brandon Jones6053a522014-07-25 16:22:09 -07002152 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002153}
2154
Brandon Jones6053a522014-07-25 16:22:09 -07002155
Jamie Madill4aa79e12014-09-29 10:46:14 -04002156void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002157{
2158 int baseWidth = getBaseLevelWidth();
2159 int baseHeight = getBaseLevelHeight();
2160 int baseDepth = getBaseLevelDepth();
2161 GLenum baseFormat = getBaseLevelInternalFormat();
2162
2163 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2164 int levelCount = mipLevels();
2165 for (int level = 1; level < levelCount; level++)
2166 {
2167 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2168 }
Brandon Jones142ec422014-07-16 10:31:30 -07002169}
2170
Jamie Madillac7579c2014-09-17 16:59:33 -04002171unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002172{
Jamie Madillc4833262014-09-18 16:18:26 -04002173 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002174}
2175
Jamie Madillac7579c2014-09-17 16:59:33 -04002176RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002177{
2178 // ensure the underlying texture is created
2179 if (!ensureRenderTarget())
2180 {
2181 return NULL;
2182 }
2183
Jamie Madillac7579c2014-09-17 16:59:33 -04002184 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002185 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002186}
2187
2188void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2189{
2190 // Only initialize the first time this texture is used as a render target or shader resource
2191 if (mTexStorage)
2192 {
2193 return;
2194 }
2195
2196 // do not attempt to create storage for nonexistant data
2197 if (!isLevelComplete(0))
2198 {
2199 return;
2200 }
2201
2202 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2203
2204 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2205 ASSERT(mTexStorage);
2206
2207 // flush image data to the storage
2208 updateStorage();
2209}
2210
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002211TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002212{
2213 GLsizei width = getBaseLevelWidth();
2214 GLsizei height = getBaseLevelHeight();
2215 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002216 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002217
2218 ASSERT(width > 0 && height > 0 && depth > 0);
2219
2220 // use existing storage level count, when previously specified by TexStorage*D
2221 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2222
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002223 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002224}
2225
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002226void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002227{
2228 SafeDelete(mTexStorage);
2229 mTexStorage = newCompleteTexStorage;
2230 mDirtyImages = true;
2231
2232 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2233 ASSERT(!mTexStorage->isManaged());
2234}
2235
2236void TextureD3D_2DArray::updateStorage()
2237{
2238 ASSERT(mTexStorage != NULL);
2239 GLint storageLevels = mTexStorage->getLevelCount();
2240 for (int level = 0; level < storageLevels; level++)
2241 {
2242 if (isLevelComplete(level))
2243 {
2244 updateStorageLevel(level);
2245 }
2246 }
2247}
2248
Brandon Jones142ec422014-07-16 10:31:30 -07002249const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2250{
2251 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2252}
2253
Brandon Jones142ec422014-07-16 10:31:30 -07002254bool TextureD3D_2DArray::isValidLevel(int level) const
2255{
2256 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2257}
2258
2259bool TextureD3D_2DArray::isLevelComplete(int level) const
2260{
2261 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2262
2263 if (isImmutable())
2264 {
2265 return true;
2266 }
2267
2268 GLsizei width = getBaseLevelWidth();
2269 GLsizei height = getBaseLevelHeight();
2270 GLsizei layers = getLayers(0);
2271
2272 if (width <= 0 || height <= 0 || layers <= 0)
2273 {
2274 return false;
2275 }
2276
2277 if (level == 0)
2278 {
2279 return true;
2280 }
2281
2282 if (getInternalFormat(level) != getInternalFormat(0))
2283 {
2284 return false;
2285 }
2286
2287 if (getWidth(level) != std::max(1, width >> level))
2288 {
2289 return false;
2290 }
2291
2292 if (getHeight(level) != std::max(1, height >> level))
2293 {
2294 return false;
2295 }
2296
2297 if (getLayers(level) != layers)
2298 {
2299 return false;
2300 }
2301
2302 return true;
2303}
2304
2305void TextureD3D_2DArray::updateStorageLevel(int level)
2306{
2307 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2308 ASSERT(isLevelComplete(level));
2309
2310 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2311 {
2312 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2313 if (mImageArray[level][layer]->isDirty())
2314 {
2315 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2316 }
2317 }
2318}
2319
2320void TextureD3D_2DArray::deleteImages()
2321{
2322 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2323 {
2324 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2325 {
2326 delete mImageArray[level][layer];
2327 }
2328 delete[] mImageArray[level];
2329 mImageArray[level] = NULL;
2330 mLayerCounts[level] = 0;
2331 }
2332}
2333
2334void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2335{
2336 // If there currently is a corresponding storage texture image, it has these parameters
2337 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2338 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2339 const int storageDepth = getLayers(0);
2340 const GLenum storageFormat = getBaseLevelInternalFormat();
2341
2342 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2343 {
2344 delete mImageArray[level][layer];
2345 }
2346 delete[] mImageArray[level];
2347 mImageArray[level] = NULL;
2348 mLayerCounts[level] = depth;
2349
2350 if (depth > 0)
2351 {
2352 mImageArray[level] = new ImageD3D*[depth]();
2353
2354 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2355 {
2356 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2357 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2358 }
2359 }
2360
2361 if (mTexStorage)
2362 {
2363 const int storageLevels = mTexStorage->getLevelCount();
2364
2365 if ((level >= storageLevels && storageLevels != 0) ||
2366 width != storageWidth ||
2367 height != storageHeight ||
2368 depth != storageDepth ||
2369 internalformat != storageFormat) // Discard mismatched storage
2370 {
2371 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2372 {
2373 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2374 {
2375 mImageArray[level][layer]->markDirty();
2376 }
2377 }
2378
2379 delete mTexStorage;
2380 mTexStorage = NULL;
2381 mDirtyImages = true;
2382 }
2383 }
2384}
2385
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002386gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
Brandon Jones142ec422014-07-16 10:31:30 -07002387{
2388 if (isValidLevel(level) && layerTarget < getLayers(level))
2389 {
2390 ImageD3D *image = mImageArray[level][layerTarget];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002391 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
2392 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002393 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002394 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002395 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002396
2397 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002398 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002399
2400 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002401}
2402
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002403gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2404{
2405 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2406}
2407
Jamie Madillcb83dc12014-09-29 10:46:12 -04002408gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2409{
2410 return gl::ImageIndex::Make2DArray(mip, layer);
2411}
2412
Brandon Jones78b1acd2014-07-15 15:33:07 -07002413}