blob: 8b458dbda13b8a12f7459da27938b93e9ffc0cbf [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
Jamie Madillba6bc952014-10-06 10:56:22 -040093gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
Jamie Madillba6bc952014-10-06 10:56:22 -040095 Image *image = getImage(index);
96
Brandon Jonesf47bebc2014-07-09 14:28:42 -070097 // No-op
98 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
99 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400100 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700101 }
102
103 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
104 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
105 const void *pixelData = pixels;
106
107 if (unpack.pixelBuffer.id() != 0)
108 {
109 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
110 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
111 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
112 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
113 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
114 const void *bufferData = pixelBuffer->getImplementation()->getData();
115 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
116 }
117
118 if (pixelData != NULL)
119 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400120 gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
121 if (error.isError())
122 {
123 return error;
124 }
125
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700126 mDirtyImages = true;
127 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400128
129 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700130}
131
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400132gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
133 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700134{
Jamie Madilldcd8f132014-10-03 19:54:50 +0000135 const void *pixelData = pixels;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700136
137 // CPU readback & copy where direct GPU copy is not supported
138 if (unpack.pixelBuffer.id() != 0)
139 {
140 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200141 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700142 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
143 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
144 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madilldcd8f132014-10-03 19:54:50 +0000145 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700146 }
147
148 if (pixelData != NULL)
149 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400150 Image *image = getImage(index);
151 ASSERT(image);
152
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400153 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
154 type, pixelData);
155 if (error.isError())
156 {
157 return error;
158 }
159
Jamie Madilldcd8f132014-10-03 19:54:50 +0000160 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madille6b6da02014-10-02 11:03:14 -0400161 error = commitRegion(index, region);
162 if (error.isError())
163 {
164 return error;
165 }
166
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700167 mDirtyImages = true;
168 }
169
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400170 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700171}
172
Geoff Langb5348332014-09-02 13:16:34 -0400173gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174{
175 if (pixels != NULL)
176 {
Geoff Langb5348332014-09-02 13:16:34 -0400177 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
178 if (error.isError())
179 {
180 return error;
181 }
182
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700183 mDirtyImages = true;
184 }
Geoff Langb5348332014-09-02 13:16:34 -0400185
186 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700187}
188
Geoff Langb5348332014-09-02 13:16:34 -0400189gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700190 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191{
192 if (pixels != NULL)
193 {
Geoff Langb5348332014-09-02 13:16:34 -0400194 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
195 if (error.isError())
196 {
197 return error;
198 }
199
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700200 mDirtyImages = true;
201 }
202
Geoff Langb5348332014-09-02 13:16:34 -0400203 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700204}
205
206bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
207{
208 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
209}
210
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400211gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
212 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700213{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400214 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700215 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
216 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400217 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700218 }
219
220 // In order to perform the fast copy through the shader, we must have the right format, and be able
221 // to create a render target.
222 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
223
Jacek Cabana5521de2014-10-01 17:23:46 +0200224 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700225
Geoff Langae5122c2014-08-27 14:08:43 -0400226 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
227 if (error.isError())
228 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400229 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400230 }
231
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400232 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700233}
234
235GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
236{
237 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
238 {
239 // Maximum number of levels
240 return gl::log2(std::max(std::max(width, height), depth)) + 1;
241 }
242 else
243 {
244 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
245 return 1;
246 }
247}
248
249int TextureD3D::mipLevels() const
250{
251 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
252}
253
Jamie Madill98553e32014-09-30 16:33:50 -0400254TextureStorage *TextureD3D::getStorage()
255{
256 return mTexStorage;
257}
258
Jamie Madill3269bcb2014-09-30 16:33:52 -0400259Image *TextureD3D::getBaseLevelImage() const
260{
261 return getImage(getImageIndex(0, 0));
262}
263
Jamie Madill4aa79e12014-09-29 10:46:14 -0400264void TextureD3D::generateMipmaps()
265{
Jamie Madilldcd8f132014-10-03 19:54:50 +0000266 // Set up proper image sizes.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400267 initMipmapsImages();
268
269 // We know that all layers have the same dimension, for the texture to be complete
270 GLint layerCount = static_cast<GLint>(getLayerCount(0));
271 GLint mipCount = mipLevels();
272
Jamie Madilldcd8f132014-10-03 19:54:50 +0000273 // The following will create and initialize the storage, or update it if it exists
274 TextureStorage *storage = getNativeTexture();
Jamie Madill4aa79e12014-09-29 10:46:14 -0400275
Jamie Madilldcd8f132014-10-03 19:54:50 +0000276 bool renderableStorage = (storage && storage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400277
278 for (GLint layer = 0; layer < layerCount; ++layer)
279 {
280 for (GLint mip = 1; mip < mipCount; ++mip)
281 {
282 ASSERT(getLayerCount(mip) == layerCount);
283
284 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
285 gl::ImageIndex destIndex = getImageIndex(mip, layer);
286
287 if (renderableStorage)
288 {
289 // GPU-side mipmapping
Jamie Madilldcd8f132014-10-03 19:54:50 +0000290 storage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400291 }
292 else
293 {
294 // CPU-side mipmapping
295 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
296 }
297 }
298 }
299}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700300
Jamie Madill135570a2014-09-30 16:33:51 -0400301bool TextureD3D::isBaseImageZeroSize() const
302{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400303 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400304
305 if (!baseImage || baseImage->getWidth() <= 0)
306 {
307 return true;
308 }
309
310 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
311 {
312 return true;
313 }
314
315 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
316 {
317 return true;
318 }
319
320 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
321 {
322 return true;
323 }
324
325 return false;
326}
327
328bool TextureD3D::ensureRenderTarget()
329{
330 initializeStorage(true);
331
332 if (!isBaseImageZeroSize())
333 {
334 ASSERT(mTexStorage);
335 if (!mTexStorage->isRenderTarget())
336 {
337 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
338
339 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
340 {
341 delete newRenderTargetStorage;
342 return gl::error(GL_OUT_OF_MEMORY, false);
343 }
344
345 setCompleteTexStorage(newRenderTargetStorage);
346 }
347 }
348
349 return (mTexStorage && mTexStorage->isRenderTarget());
350}
351
Brandon Jones78b1acd2014-07-15 15:33:07 -0700352TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400353 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700354{
355 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
356 {
357 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
358 }
359}
360
361TextureD3D_2D::~TextureD3D_2D()
362{
Austin Kinross69822602014-08-12 15:51:37 -0700363 // Delete the Images before the TextureStorage.
364 // Images might be relying on the TextureStorage for some of their data.
365 // 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 -0700366 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
367 {
368 delete mImageArray[i];
369 }
Austin Kinross69822602014-08-12 15:51:37 -0700370
371 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700372}
373
Brandon Jonescef06ff2014-08-05 13:27:48 -0700374Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700375{
376 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700377 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700378 return mImageArray[level];
379}
380
Jamie Madillfeda4d22014-09-17 13:03:29 -0400381Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
382{
383 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400384 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400385 ASSERT(index.type == GL_TEXTURE_2D);
386 return mImageArray[index.mipIndex];
387}
388
Brandon Jonescef06ff2014-08-05 13:27:48 -0700389GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700390{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700391 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
392 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700393}
394
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700395GLsizei TextureD3D_2D::getWidth(GLint level) const
396{
397 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
398 return mImageArray[level]->getWidth();
399 else
400 return 0;
401}
402
403GLsizei TextureD3D_2D::getHeight(GLint level) const
404{
405 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
406 return mImageArray[level]->getHeight();
407 else
408 return 0;
409}
410
411GLenum TextureD3D_2D::getInternalFormat(GLint level) const
412{
413 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
414 return mImageArray[level]->getInternalFormat();
415 else
416 return GL_NONE;
417}
418
419GLenum TextureD3D_2D::getActualFormat(GLint level) const
420{
421 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
422 return mImageArray[level]->getActualFormat();
423 else
424 return GL_NONE;
425}
426
427bool TextureD3D_2D::isDepth(GLint level) const
428{
Geoff Lang5d601382014-07-22 15:14:06 -0400429 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700430}
431
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400432gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
433 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
434 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700436 ASSERT(target == GL_TEXTURE_2D && depth == 1);
437
Geoff Lang5d601382014-07-22 15:14:06 -0400438 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
439
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440 bool fastUnpacked = false;
441
Brandon Jonescef06ff2014-08-05 13:27:48 -0700442 redefineImage(level, sizedInternalFormat, width, height);
443
Jamie Madillba6bc952014-10-06 10:56:22 -0400444 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
445
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700446 // Attempt a fast gpu copy of the pixel data to the surface
447 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
448 {
449 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400450 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700451 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
452
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400453 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700454 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400455 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
456 if (error.isError())
457 {
458 return error;
459 }
460
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461 // Ensure we don't overwrite our newly initialized data
462 mImageArray[level]->markClean();
463
464 fastUnpacked = true;
465 }
466 }
467
468 if (!fastUnpacked)
469 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400470 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400471 if (error.isError())
472 {
473 return error;
474 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700475 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400476
477 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700478}
479
Geoff Langb5348332014-09-02 13:16:34 -0400480gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
481 GLsizei width, GLsizei height, GLsizei depth,
482 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700483{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700484 ASSERT(target == GL_TEXTURE_2D && depth == 1);
485
486 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
487 redefineImage(level, format, width, height);
488
Geoff Langb5348332014-09-02 13:16:34 -0400489 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700490}
491
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400492gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
493 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
494 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700495{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700496 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
497
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700498 bool fastUnpacked = false;
499
Jamie Madillac7579c2014-09-17 16:59:33 -0400500 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400501 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700502 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
503 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400504 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400506 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700507 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400508 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
509 if (error.isError())
510 {
511 return error;
512 }
513
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700514 // Ensure we don't overwrite our newly initialized data
515 mImageArray[level]->markClean();
516
517 fastUnpacked = true;
518 }
519 }
520
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400521 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400523 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
524 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700525 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400526
527 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528}
529
Geoff Langb5348332014-09-02 13:16:34 -0400530gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
531 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
532 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700533{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700534 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
535
Geoff Langb5348332014-09-02 13:16:34 -0400536 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
537 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538 {
Geoff Langb5348332014-09-02 13:16:34 -0400539 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540 }
Geoff Langb5348332014-09-02 13:16:34 -0400541
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400542 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
543 gl::Box region(xoffset, yoffset, 0, width, height, 1);
544 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700545}
546
Brandon Jonescef06ff2014-08-05 13:27:48 -0700547void 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 -0700548{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700549 ASSERT(target == GL_TEXTURE_2D);
550
551 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
552 redefineImage(level, sizedInternalFormat, width, height);
553
Jamie Madill82bf0c52014-10-03 11:50:53 -0400554 gl::Rectangle sourceRect(x, y, width, height);
555
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700556 if (!mImageArray[level]->isRenderableFormat())
557 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400558 mImageArray[level]->copy(0, 0, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700559 mDirtyImages = true;
560 }
561 else
562 {
563 ensureRenderTarget();
564 mImageArray[level]->markClean();
565
566 if (width != 0 && height != 0 && isValidLevel(level))
567 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400568 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700569 }
570 }
571}
572
573void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
574{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700575 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
576
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700577 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
578 // the current level we're copying to is defined (with appropriate format, width & height)
579 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
580
Jamie Madill82bf0c52014-10-03 11:50:53 -0400581 gl::Rectangle sourceRect(x, y, width, height);
582
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
584 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400585 mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586 mDirtyImages = true;
587 }
588 else
589 {
590 ensureRenderTarget();
591
592 if (isValidLevel(level))
593 {
594 updateStorageLevel(level);
595
Jamie Madill856d9d42014-09-18 15:08:49 -0400596 mRenderer->copyImage2D(source, sourceRect,
597 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
598 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599 }
600 }
601}
602
Brandon Jonescef06ff2014-08-05 13:27:48 -0700603void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700605 ASSERT(target == GL_TEXTURE_2D && depth == 1);
606
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700607 for (int level = 0; level < levels; level++)
608 {
609 GLsizei levelWidth = std::max(1, width >> level);
610 GLsizei levelHeight = std::max(1, height >> level);
611 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
612 }
613
614 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
615 {
616 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
617 }
618
619 mImmutable = true;
620
Jamie Madillc4833262014-09-18 16:18:26 -0400621 bool renderTarget = IsRenderTargetUsage(mUsage);
622 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400623 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700624}
625
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626void TextureD3D_2D::bindTexImage(egl::Surface *surface)
627{
628 GLenum internalformat = surface->getFormat();
629
630 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
631
632 if (mTexStorage)
633 {
634 SafeDelete(mTexStorage);
635 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400636
637 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638
639 mDirtyImages = true;
640}
641
642void TextureD3D_2D::releaseTexImage()
643{
644 if (mTexStorage)
645 {
646 SafeDelete(mTexStorage);
647 }
648
649 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
650 {
651 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
652 }
653}
654
Jamie Madill4aa79e12014-09-29 10:46:14 -0400655void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700657 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700658 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700659 for (int level = 1; level < levelCount; level++)
660 {
661 redefineImage(level, getBaseLevelInternalFormat(),
662 std::max(getBaseLevelWidth() >> level, 1),
663 std::max(getBaseLevelHeight() >> level, 1));
664 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665}
666
Jamie Madillac7579c2014-09-17 16:59:33 -0400667unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700668{
Jamie Madillac7579c2014-09-17 16:59:33 -0400669 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400670 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671}
672
Jamie Madillac7579c2014-09-17 16:59:33 -0400673RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674{
Jamie Madillac7579c2014-09-17 16:59:33 -0400675 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700676
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677 // ensure the underlying texture is created
678 if (!ensureRenderTarget())
679 {
680 return NULL;
681 }
682
Jamie Madillac7579c2014-09-17 16:59:33 -0400683 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400684 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700685}
686
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700687bool TextureD3D_2D::isValidLevel(int level) const
688{
689 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
690}
691
692bool TextureD3D_2D::isLevelComplete(int level) const
693{
694 if (isImmutable())
695 {
696 return true;
697 }
698
Brandon Jones78b1acd2014-07-15 15:33:07 -0700699 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700700
701 GLsizei width = baseImage->getWidth();
702 GLsizei height = baseImage->getHeight();
703
704 if (width <= 0 || height <= 0)
705 {
706 return false;
707 }
708
709 // The base image level is complete if the width and height are positive
710 if (level == 0)
711 {
712 return true;
713 }
714
715 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700716 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700717
718 if (image->getInternalFormat() != baseImage->getInternalFormat())
719 {
720 return false;
721 }
722
723 if (image->getWidth() != std::max(1, width >> level))
724 {
725 return false;
726 }
727
728 if (image->getHeight() != std::max(1, height >> level))
729 {
730 return false;
731 }
732
733 return true;
734}
735
736// Constructs a native texture resource from the texture images
737void TextureD3D_2D::initializeStorage(bool renderTarget)
738{
739 // Only initialize the first time this texture is used as a render target or shader resource
740 if (mTexStorage)
741 {
742 return;
743 }
744
745 // do not attempt to create storage for nonexistant data
746 if (!isLevelComplete(0))
747 {
748 return;
749 }
750
751 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
752
753 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
754 ASSERT(mTexStorage);
755
756 // flush image data to the storage
757 updateStorage();
758}
759
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400760TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700761{
762 GLsizei width = getBaseLevelWidth();
763 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400764 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765
766 ASSERT(width > 0 && height > 0);
767
768 // use existing storage level count, when previously specified by TexStorage*D
769 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
770
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400771 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700772}
773
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400774void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700775{
776 SafeDelete(mTexStorage);
777 mTexStorage = newCompleteTexStorage;
778
779 if (mTexStorage && mTexStorage->isManaged())
780 {
781 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
782 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400783 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700784 }
785 }
786
787 mDirtyImages = true;
788}
789
790void TextureD3D_2D::updateStorage()
791{
792 ASSERT(mTexStorage != NULL);
793 GLint storageLevels = mTexStorage->getLevelCount();
794 for (int level = 0; level < storageLevels; level++)
795 {
796 if (mImageArray[level]->isDirty() && isLevelComplete(level))
797 {
798 updateStorageLevel(level);
799 }
800 }
801}
802
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700803void TextureD3D_2D::updateStorageLevel(int level)
804{
805 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
806 ASSERT(isLevelComplete(level));
807
808 if (mImageArray[level]->isDirty())
809 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400810 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
811 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
812 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813 }
814}
815
816void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
817{
818 // If there currently is a corresponding storage texture image, it has these parameters
819 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
820 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
821 const GLenum storageFormat = getBaseLevelInternalFormat();
822
823 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
824
825 if (mTexStorage)
826 {
827 const int storageLevels = mTexStorage->getLevelCount();
828
829 if ((level >= storageLevels && storageLevels != 0) ||
830 width != storageWidth ||
831 height != storageHeight ||
832 internalformat != storageFormat) // Discard mismatched storage
833 {
834 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
835 {
836 mImageArray[i]->markDirty();
837 }
838
839 SafeDelete(mTexStorage);
840 mDirtyImages = true;
841 }
842 }
843}
844
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400845gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700846{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400847 ASSERT(!index.hasLayer());
848 GLint level = index.mipIndex;
849
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700850 if (isValidLevel(level))
851 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700852 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -0400853 gl::Error error = image->copyToStorage2D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400854 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700855 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400856 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700857 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400858
859 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700860 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400861
862 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863}
864
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400865gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
866{
867 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
868}
Brandon Jones0511e802014-07-14 16:27:26 -0700869
Jamie Madillcb83dc12014-09-29 10:46:12 -0400870gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
871{
872 // "layer" does not apply to 2D Textures.
873 return gl::ImageIndex::Make2D(mip);
874}
875
Brandon Jones78b1acd2014-07-15 15:33:07 -0700876TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400877 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700878{
879 for (int i = 0; i < 6; i++)
880 {
881 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
882 {
883 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
884 }
885 }
886}
887
888TextureD3D_Cube::~TextureD3D_Cube()
889{
Austin Kinross69822602014-08-12 15:51:37 -0700890 // Delete the Images before the TextureStorage.
891 // Images might be relying on the TextureStorage for some of their data.
892 // 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 -0700893 for (int i = 0; i < 6; i++)
894 {
895 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
896 {
897 SafeDelete(mImageArray[i][j]);
898 }
899 }
Austin Kinross69822602014-08-12 15:51:37 -0700900
901 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700902}
903
Brandon Jonescef06ff2014-08-05 13:27:48 -0700904Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700905{
906 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700907 ASSERT(layer < 6);
908 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700909}
910
Jamie Madillfeda4d22014-09-17 13:03:29 -0400911Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
912{
913 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
914 ASSERT(index.layerIndex < 6);
915 return mImageArray[index.layerIndex][index.mipIndex];
916}
917
Brandon Jonescef06ff2014-08-05 13:27:48 -0700918GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700919{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700920 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
921 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700922}
923
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700925{
926 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700927 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700928 else
929 return GL_NONE;
930}
931
Brandon Jonescef06ff2014-08-05 13:27:48 -0700932bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700933{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700934 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700935}
936
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400937gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
938 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
939 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700940{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700941 ASSERT(depth == 1);
942
Geoff Lang5d601382014-07-22 15:14:06 -0400943 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -0400944 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700945
Jamie Madillba6bc952014-10-06 10:56:22 -0400946 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -0700947
Jamie Madillba6bc952014-10-06 10:56:22 -0400948 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -0700949}
950
Geoff Langb5348332014-09-02 13:16:34 -0400951gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
952 GLsizei width, GLsizei height, GLsizei depth,
953 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700954{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700955 ASSERT(depth == 1);
956
Brandon Jones0511e802014-07-14 16:27:26 -0700957 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700958 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
959
Brandon Jones0511e802014-07-14 16:27:26 -0700960 redefineImage(faceIndex, level, format, width, height);
961
Geoff Langb5348332014-09-02 13:16:34 -0400962 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700963}
964
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400965gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
966 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
967 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700968{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700969 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400970 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -0400971 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -0700972}
973
Geoff Langb5348332014-09-02 13:16:34 -0400974gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
975 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
976 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700977{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700978 ASSERT(depth == 1 && zoffset == 0);
979
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400980 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700981
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400982 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -0400983 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700984 {
Geoff Langb5348332014-09-02 13:16:34 -0400985 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700986 }
Geoff Langb5348332014-09-02 13:16:34 -0400987
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400988 gl::Box region(xoffset, yoffset, 0, width, height, 1);
989 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -0700990}
991
992void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
993{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700994 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400995 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
996
Brandon Jones0511e802014-07-14 16:27:26 -0700997 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
998
Jamie Madill82bf0c52014-10-03 11:50:53 -0400999 gl::Rectangle sourceRect(x, y, width, height);
1000
Brandon Jones0511e802014-07-14 16:27:26 -07001001 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1002 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001003 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001004 mDirtyImages = true;
1005 }
1006 else
1007 {
1008 ensureRenderTarget();
1009 mImageArray[faceIndex][level]->markClean();
1010
1011 ASSERT(width == height);
1012
1013 if (width > 0 && isValidFaceLevel(faceIndex, level))
1014 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001015 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001016 }
1017 }
1018}
1019
1020void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1021{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001022 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001023
1024 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1025 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1026 // rely on the "getBaseLevel*" methods reliably otherwise.
1027 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1028
Jamie Madill82bf0c52014-10-03 11:50:53 -04001029 gl::Rectangle sourceRect(x, y, width, height);
1030
Brandon Jones0511e802014-07-14 16:27:26 -07001031 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1032 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001033 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001034 mDirtyImages = true;
1035 }
1036 else
1037 {
1038 ensureRenderTarget();
1039
1040 if (isValidFaceLevel(faceIndex, level))
1041 {
1042 updateStorageFaceLevel(faceIndex, level);
1043
Jamie Madill856d9d42014-09-18 15:08:49 -04001044 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1045 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001046 }
1047 }
1048}
1049
Brandon Jonescef06ff2014-08-05 13:27:48 -07001050void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001051{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001052 ASSERT(width == height);
1053 ASSERT(depth == 1);
1054
Brandon Jones0511e802014-07-14 16:27:26 -07001055 for (int level = 0; level < levels; level++)
1056 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001057 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001058 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1059 {
1060 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1061 }
1062 }
1063
1064 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1065 {
1066 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1067 {
1068 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1069 }
1070 }
1071
1072 mImmutable = true;
1073
Jamie Madillc4833262014-09-18 16:18:26 -04001074 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001075 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1076 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001077}
1078
Brandon Jones0511e802014-07-14 16:27:26 -07001079// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1080bool TextureD3D_Cube::isCubeComplete() const
1081{
1082 int baseWidth = getBaseLevelWidth();
1083 int baseHeight = getBaseLevelHeight();
1084 GLenum baseFormat = getBaseLevelInternalFormat();
1085
1086 if (baseWidth <= 0 || baseWidth != baseHeight)
1087 {
1088 return false;
1089 }
1090
1091 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1092 {
1093 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1094
1095 if (faceBaseImage.getWidth() != baseWidth ||
1096 faceBaseImage.getHeight() != baseHeight ||
1097 faceBaseImage.getInternalFormat() != baseFormat )
1098 {
1099 return false;
1100 }
1101 }
1102
1103 return true;
1104}
1105
Brandon Jones6053a522014-07-25 16:22:09 -07001106void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1107{
1108 UNREACHABLE();
1109}
1110
1111void TextureD3D_Cube::releaseTexImage()
1112{
1113 UNREACHABLE();
1114}
1115
1116
Jamie Madill4aa79e12014-09-29 10:46:14 -04001117void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001118{
1119 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1120 int levelCount = mipLevels();
1121 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1122 {
1123 for (int level = 1; level < levelCount; level++)
1124 {
1125 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1126 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1127 }
1128 }
Brandon Jones0511e802014-07-14 16:27:26 -07001129}
1130
Jamie Madillac7579c2014-09-17 16:59:33 -04001131unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
Jamie Madillc4833262014-09-18 16:18:26 -04001133 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001134}
1135
Jamie Madillac7579c2014-09-17 16:59:33 -04001136RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001137{
Jamie Madillac7579c2014-09-17 16:59:33 -04001138 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001139
1140 // ensure the underlying texture is created
1141 if (!ensureRenderTarget())
1142 {
1143 return NULL;
1144 }
1145
Jamie Madillac7579c2014-09-17 16:59:33 -04001146 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001147 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001148}
1149
Brandon Jones0511e802014-07-14 16:27:26 -07001150void TextureD3D_Cube::initializeStorage(bool renderTarget)
1151{
1152 // Only initialize the first time this texture is used as a render target or shader resource
1153 if (mTexStorage)
1154 {
1155 return;
1156 }
1157
1158 // do not attempt to create storage for nonexistant data
1159 if (!isFaceLevelComplete(0, 0))
1160 {
1161 return;
1162 }
1163
1164 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1165
1166 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1167 ASSERT(mTexStorage);
1168
1169 // flush image data to the storage
1170 updateStorage();
1171}
1172
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001173TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001174{
1175 GLsizei size = getBaseLevelWidth();
1176
1177 ASSERT(size > 0);
1178
1179 // use existing storage level count, when previously specified by TexStorage*D
1180 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1181
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001182 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001183}
1184
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001185void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001186{
1187 SafeDelete(mTexStorage);
1188 mTexStorage = newCompleteTexStorage;
1189
1190 if (mTexStorage && mTexStorage->isManaged())
1191 {
1192 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1193 {
1194 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1195 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001196 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001197 }
1198 }
1199 }
1200
1201 mDirtyImages = true;
1202}
1203
1204void TextureD3D_Cube::updateStorage()
1205{
1206 ASSERT(mTexStorage != NULL);
1207 GLint storageLevels = mTexStorage->getLevelCount();
1208 for (int face = 0; face < 6; face++)
1209 {
1210 for (int level = 0; level < storageLevels; level++)
1211 {
1212 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1213 {
1214 updateStorageFaceLevel(face, level);
1215 }
1216 }
1217 }
1218}
1219
Brandon Jones0511e802014-07-14 16:27:26 -07001220bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1221{
1222 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1223}
1224
Brandon Jones0511e802014-07-14 16:27:26 -07001225bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1226{
1227 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1228
1229 if (isImmutable())
1230 {
1231 return true;
1232 }
1233
1234 int baseSize = getBaseLevelWidth();
1235
1236 if (baseSize <= 0)
1237 {
1238 return false;
1239 }
1240
1241 // "isCubeComplete" checks for base level completeness and we must call that
1242 // to determine if any face at level 0 is complete. We omit that check here
1243 // to avoid re-checking cube-completeness for every face at level 0.
1244 if (level == 0)
1245 {
1246 return true;
1247 }
1248
1249 // Check that non-zero levels are consistent with the base level.
1250 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1251
1252 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1253 {
1254 return false;
1255 }
1256
1257 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1258 {
1259 return false;
1260 }
1261
1262 return true;
1263}
1264
1265void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1266{
1267 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1268 ImageD3D *image = mImageArray[faceIndex][level];
1269
1270 if (image->isDirty())
1271 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001272 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1273 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1274 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1275 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001276 }
1277}
1278
1279void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1280{
1281 // If there currently is a corresponding storage texture image, it has these parameters
1282 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1283 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1284 const GLenum storageFormat = getBaseLevelInternalFormat();
1285
1286 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1287
1288 if (mTexStorage)
1289 {
1290 const int storageLevels = mTexStorage->getLevelCount();
1291
1292 if ((level >= storageLevels && storageLevels != 0) ||
1293 width != storageWidth ||
1294 height != storageHeight ||
1295 internalformat != storageFormat) // Discard mismatched storage
1296 {
1297 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1298 {
1299 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1300 {
1301 mImageArray[faceIndex][level]->markDirty();
1302 }
1303 }
1304
1305 SafeDelete(mTexStorage);
1306
1307 mDirtyImages = true;
1308 }
1309 }
1310}
1311
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001312gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001313{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001314 ASSERT(index.hasLayer());
1315
1316 GLint level = index.mipIndex;
1317 int faceIndex = static_cast<int>(index.layerIndex);
1318
Brandon Jones0511e802014-07-14 16:27:26 -07001319 if (isValidFaceLevel(faceIndex, level))
1320 {
1321 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001322 gl::Error error = image->copyToStorageCube(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001323 if (error.isError())
1324 {
1325 return error;
1326 }
1327
1328 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001329 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001330
1331 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001332}
1333
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001334gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1335{
1336 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1337}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001338
Jamie Madillcb83dc12014-09-29 10:46:12 -04001339gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1340{
1341 // The "layer" of the image index corresponds to the cube face
1342 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1343}
1344
Brandon Jones78b1acd2014-07-15 15:33:07 -07001345TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001346 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001347{
1348 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1349 {
1350 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1351 }
1352}
1353
1354TextureD3D_3D::~TextureD3D_3D()
1355{
Austin Kinross69822602014-08-12 15:51:37 -07001356 // Delete the Images before the TextureStorage.
1357 // Images might be relying on the TextureStorage for some of their data.
1358 // 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 -07001359 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1360 {
1361 delete mImageArray[i];
1362 }
Austin Kinross69822602014-08-12 15:51:37 -07001363
1364 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001365}
1366
Brandon Jonescef06ff2014-08-05 13:27:48 -07001367Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001368{
1369 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001370 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001371 return mImageArray[level];
1372}
1373
Jamie Madillfeda4d22014-09-17 13:03:29 -04001374Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1375{
1376 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001377 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001378 ASSERT(index.type == GL_TEXTURE_3D);
1379 return mImageArray[index.mipIndex];
1380}
1381
Brandon Jonescef06ff2014-08-05 13:27:48 -07001382GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001383{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001384 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1385 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386}
1387
Brandon Jones78b1acd2014-07-15 15:33:07 -07001388GLsizei TextureD3D_3D::getWidth(GLint level) const
1389{
1390 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1391 return mImageArray[level]->getWidth();
1392 else
1393 return 0;
1394}
1395
1396GLsizei TextureD3D_3D::getHeight(GLint level) const
1397{
1398 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1399 return mImageArray[level]->getHeight();
1400 else
1401 return 0;
1402}
1403
1404GLsizei TextureD3D_3D::getDepth(GLint level) const
1405{
1406 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1407 return mImageArray[level]->getDepth();
1408 else
1409 return 0;
1410}
1411
1412GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1413{
1414 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1415 return mImageArray[level]->getInternalFormat();
1416 else
1417 return GL_NONE;
1418}
1419
1420bool TextureD3D_3D::isDepth(GLint level) const
1421{
Geoff Lang5d601382014-07-22 15:14:06 -04001422 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001423}
1424
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001425gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1426 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1427 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001428{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001429 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001430 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1431
Brandon Jones78b1acd2014-07-15 15:33:07 -07001432 redefineImage(level, sizedInternalFormat, width, height, depth);
1433
1434 bool fastUnpacked = false;
1435
Jamie Madillba6bc952014-10-06 10:56:22 -04001436 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1437
Brandon Jones78b1acd2014-07-15 15:33:07 -07001438 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1439 if (isFastUnpackable(unpack, sizedInternalFormat))
1440 {
1441 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001442 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001443 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1444
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001445 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001446 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001447 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1448 if (error.isError())
1449 {
1450 return error;
1451 }
1452
Brandon Jones78b1acd2014-07-15 15:33:07 -07001453 // Ensure we don't overwrite our newly initialized data
1454 mImageArray[level]->markClean();
1455
1456 fastUnpacked = true;
1457 }
1458 }
1459
1460 if (!fastUnpacked)
1461 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001462 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001463 if (error.isError())
1464 {
1465 return error;
1466 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001467 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001468
1469 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001470}
1471
Geoff Langb5348332014-09-02 13:16:34 -04001472gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1473 GLsizei width, GLsizei height,GLsizei depth,
1474 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001476 ASSERT(target == GL_TEXTURE_3D);
1477
Brandon Jones78b1acd2014-07-15 15:33:07 -07001478 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1479 redefineImage(level, format, width, height, depth);
1480
Geoff Langb5348332014-09-02 13:16:34 -04001481 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001482}
1483
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001484gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1485 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1486 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001487{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001488 ASSERT(target == GL_TEXTURE_3D);
1489
Brandon Jones78b1acd2014-07-15 15:33:07 -07001490 bool fastUnpacked = false;
1491
Jamie Madillac7579c2014-09-17 16:59:33 -04001492 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1493
Brandon Jones78b1acd2014-07-15 15:33:07 -07001494 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1495 if (isFastUnpackable(unpack, getInternalFormat(level)))
1496 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001497 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001498
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001499 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001501 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001502 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1503 if (error.isError())
1504 {
1505 return error;
1506 }
1507
Brandon Jones78b1acd2014-07-15 15:33:07 -07001508 // Ensure we don't overwrite our newly initialized data
1509 mImageArray[level]->markClean();
1510
1511 fastUnpacked = true;
1512 }
1513 }
1514
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001515 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001517 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1518 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001519 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001520
1521 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001522}
1523
Geoff Langb5348332014-09-02 13:16:34 -04001524gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1525 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1526 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001527{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001528 ASSERT(target == GL_TEXTURE_3D);
1529
Geoff Langb5348332014-09-02 13:16:34 -04001530 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1531 format, imageSize, pixels, mImageArray[level]);
1532 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001533 {
Geoff Langb5348332014-09-02 13:16:34 -04001534 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535 }
Geoff Langb5348332014-09-02 13:16:34 -04001536
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001537 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1538 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1539 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540}
1541
Brandon Jonescef06ff2014-08-05 13:27:48 -07001542void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1543{
1544 UNIMPLEMENTED();
1545}
1546
Brandon Jones78b1acd2014-07-15 15:33:07 -07001547void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1548{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001549 ASSERT(target == GL_TEXTURE_3D);
1550
Brandon Jones78b1acd2014-07-15 15:33:07 -07001551 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1552 // the current level we're copying to is defined (with appropriate format, width & height)
1553 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1554
Jamie Madill82bf0c52014-10-03 11:50:53 -04001555 gl::Rectangle sourceRect(x, y, width, height);
1556
Brandon Jones78b1acd2014-07-15 15:33:07 -07001557 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1558 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001559 mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001560 mDirtyImages = true;
1561 }
1562 else
1563 {
1564 ensureRenderTarget();
1565
1566 if (isValidLevel(level))
1567 {
1568 updateStorageLevel(level);
1569
Jamie Madill856d9d42014-09-18 15:08:49 -04001570 mRenderer->copyImage3D(source, sourceRect,
1571 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1572 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001573 }
1574 }
1575}
1576
Brandon Jonescef06ff2014-08-05 13:27:48 -07001577void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001578{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001579 ASSERT(target == GL_TEXTURE_3D);
1580
Brandon Jones78b1acd2014-07-15 15:33:07 -07001581 for (int level = 0; level < levels; level++)
1582 {
1583 GLsizei levelWidth = std::max(1, width >> level);
1584 GLsizei levelHeight = std::max(1, height >> level);
1585 GLsizei levelDepth = std::max(1, depth >> level);
1586 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1587 }
1588
1589 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1590 {
1591 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1592 }
1593
1594 mImmutable = true;
1595
Jamie Madillc4833262014-09-18 16:18:26 -04001596 bool renderTarget = IsRenderTargetUsage(mUsage);
1597 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001598 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001599}
1600
Brandon Jones6053a522014-07-25 16:22:09 -07001601void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001602{
Brandon Jones6053a522014-07-25 16:22:09 -07001603 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001604}
1605
Brandon Jones6053a522014-07-25 16:22:09 -07001606void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001607{
Brandon Jones6053a522014-07-25 16:22:09 -07001608 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001609}
1610
Brandon Jones6053a522014-07-25 16:22:09 -07001611
Jamie Madill4aa79e12014-09-29 10:46:14 -04001612void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001613{
1614 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1615 int levelCount = mipLevels();
1616 for (int level = 1; level < levelCount; level++)
1617 {
1618 redefineImage(level, getBaseLevelInternalFormat(),
1619 std::max(getBaseLevelWidth() >> level, 1),
1620 std::max(getBaseLevelHeight() >> level, 1),
1621 std::max(getBaseLevelDepth() >> level, 1));
1622 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001623}
1624
Jamie Madillac7579c2014-09-17 16:59:33 -04001625unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626{
Jamie Madillc4833262014-09-18 16:18:26 -04001627 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001628}
1629
Jamie Madillac7579c2014-09-17 16:59:33 -04001630RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001631{
1632 // ensure the underlying texture is created
1633 if (!ensureRenderTarget())
1634 {
1635 return NULL;
1636 }
1637
Jamie Madillac7579c2014-09-17 16:59:33 -04001638 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001640 updateStorage();
1641 }
1642 else
1643 {
1644 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001645 }
1646
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001647 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001648}
1649
1650void TextureD3D_3D::initializeStorage(bool renderTarget)
1651{
1652 // Only initialize the first time this texture is used as a render target or shader resource
1653 if (mTexStorage)
1654 {
1655 return;
1656 }
1657
1658 // do not attempt to create storage for nonexistant data
1659 if (!isLevelComplete(0))
1660 {
1661 return;
1662 }
1663
1664 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1665
1666 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1667 ASSERT(mTexStorage);
1668
1669 // flush image data to the storage
1670 updateStorage();
1671}
1672
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001673TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674{
1675 GLsizei width = getBaseLevelWidth();
1676 GLsizei height = getBaseLevelHeight();
1677 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001678 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001679
1680 ASSERT(width > 0 && height > 0 && depth > 0);
1681
1682 // use existing storage level count, when previously specified by TexStorage*D
1683 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1684
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001685 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001686}
1687
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001688void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001689{
1690 SafeDelete(mTexStorage);
1691 mTexStorage = newCompleteTexStorage;
1692 mDirtyImages = true;
1693
1694 // We do not support managed 3D storage, as that is D3D9/ES2-only
1695 ASSERT(!mTexStorage->isManaged());
1696}
1697
1698void TextureD3D_3D::updateStorage()
1699{
1700 ASSERT(mTexStorage != NULL);
1701 GLint storageLevels = mTexStorage->getLevelCount();
1702 for (int level = 0; level < storageLevels; level++)
1703 {
1704 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1705 {
1706 updateStorageLevel(level);
1707 }
1708 }
1709}
1710
Brandon Jones78b1acd2014-07-15 15:33:07 -07001711bool TextureD3D_3D::isValidLevel(int level) const
1712{
1713 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1714}
1715
1716bool TextureD3D_3D::isLevelComplete(int level) const
1717{
1718 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1719
1720 if (isImmutable())
1721 {
1722 return true;
1723 }
1724
1725 GLsizei width = getBaseLevelWidth();
1726 GLsizei height = getBaseLevelHeight();
1727 GLsizei depth = getBaseLevelDepth();
1728
1729 if (width <= 0 || height <= 0 || depth <= 0)
1730 {
1731 return false;
1732 }
1733
1734 if (level == 0)
1735 {
1736 return true;
1737 }
1738
1739 ImageD3D *levelImage = mImageArray[level];
1740
1741 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1742 {
1743 return false;
1744 }
1745
1746 if (levelImage->getWidth() != std::max(1, width >> level))
1747 {
1748 return false;
1749 }
1750
1751 if (levelImage->getHeight() != std::max(1, height >> level))
1752 {
1753 return false;
1754 }
1755
1756 if (levelImage->getDepth() != std::max(1, depth >> level))
1757 {
1758 return false;
1759 }
1760
1761 return true;
1762}
1763
1764void TextureD3D_3D::updateStorageLevel(int level)
1765{
1766 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1767 ASSERT(isLevelComplete(level));
1768
1769 if (mImageArray[level]->isDirty())
1770 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001771 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1772 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1773 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001774 }
1775}
1776
1777void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1778{
1779 // If there currently is a corresponding storage texture image, it has these parameters
1780 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1781 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1782 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1783 const GLenum storageFormat = getBaseLevelInternalFormat();
1784
1785 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1786
1787 if (mTexStorage)
1788 {
1789 const int storageLevels = mTexStorage->getLevelCount();
1790
1791 if ((level >= storageLevels && storageLevels != 0) ||
1792 width != storageWidth ||
1793 height != storageHeight ||
1794 depth != storageDepth ||
1795 internalformat != storageFormat) // Discard mismatched storage
1796 {
1797 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1798 {
1799 mImageArray[i]->markDirty();
1800 }
1801
1802 SafeDelete(mTexStorage);
1803 mDirtyImages = true;
1804 }
1805 }
1806}
1807
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001808gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001810 ASSERT(!index.hasLayer());
1811 GLint level = index.mipIndex;
1812
Brandon Jones78b1acd2014-07-15 15:33:07 -07001813 if (isValidLevel(level))
1814 {
1815 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001816 gl::Error error = image->copyToStorage3D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001817 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001818 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001819 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001820 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001821
1822 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001823 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001824
1825 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001826}
1827
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001828gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1829{
1830 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1831 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1832}
Brandon Jones142ec422014-07-16 10:31:30 -07001833
Jamie Madillcb83dc12014-09-29 10:46:12 -04001834gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1835{
1836 // The "layer" here does not apply to 3D images. We use one Image per mip.
1837 return gl::ImageIndex::Make3D(mip);
1838}
1839
Brandon Jones142ec422014-07-16 10:31:30 -07001840TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001841 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001842{
1843 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1844 {
1845 mLayerCounts[level] = 0;
1846 mImageArray[level] = NULL;
1847 }
1848}
1849
1850TextureD3D_2DArray::~TextureD3D_2DArray()
1851{
Austin Kinross69822602014-08-12 15:51:37 -07001852 // Delete the Images before the TextureStorage.
1853 // Images might be relying on the TextureStorage for some of their data.
1854 // 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 -07001855 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001856 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001857}
1858
Brandon Jones142ec422014-07-16 10:31:30 -07001859Image *TextureD3D_2DArray::getImage(int level, int layer) const
1860{
1861 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1862 ASSERT(layer < mLayerCounts[level]);
1863 return mImageArray[level][layer];
1864}
1865
Jamie Madillfeda4d22014-09-17 13:03:29 -04001866Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1867{
1868 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1869 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1870 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1871 return mImageArray[index.mipIndex][index.layerIndex];
1872}
1873
Brandon Jones142ec422014-07-16 10:31:30 -07001874GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1875{
1876 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1877 return mLayerCounts[level];
1878}
1879
Brandon Jones142ec422014-07-16 10:31:30 -07001880GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1881{
1882 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1883}
1884
1885GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1886{
1887 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1888}
1889
Brandon Jones142ec422014-07-16 10:31:30 -07001890GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1891{
1892 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1893}
1894
1895bool TextureD3D_2DArray::isDepth(GLint level) const
1896{
Geoff Lang5d601382014-07-22 15:14:06 -04001897 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001898}
1899
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001900gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1901 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1902 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001903{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001904 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1905
Geoff Lang5d601382014-07-22 15:14:06 -04001906 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1907
Brandon Jones142ec422014-07-16 10:31:30 -07001908 redefineImage(level, sizedInternalFormat, width, height, depth);
1909
Geoff Lang5d601382014-07-22 15:14:06 -04001910 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1911 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001912
1913 for (int i = 0; i < depth; i++)
1914 {
1915 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04001916 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
1917 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001918 if (error.isError())
1919 {
1920 return error;
1921 }
Brandon Jones142ec422014-07-16 10:31:30 -07001922 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001923
1924 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001925}
1926
Geoff Langb5348332014-09-02 13:16:34 -04001927gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1928 GLsizei width, GLsizei height, GLsizei depth,
1929 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001930{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001931 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1932
Brandon Jones142ec422014-07-16 10:31:30 -07001933 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1934 redefineImage(level, format, width, height, depth);
1935
Geoff Lang5d601382014-07-22 15:14:06 -04001936 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1937 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001938
1939 for (int i = 0; i < depth; i++)
1940 {
1941 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001942 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1943 if (error.isError())
1944 {
1945 return error;
1946 }
Brandon Jones142ec422014-07-16 10:31:30 -07001947 }
Geoff Langb5348332014-09-02 13:16:34 -04001948
1949 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001950}
1951
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001952gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1953 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1954 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001955{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001956 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1957
Geoff Lang5d601382014-07-22 15:14:06 -04001958 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1959 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001960
1961 for (int i = 0; i < depth; i++)
1962 {
1963 int layer = zoffset + i;
1964 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1965
Jamie Madillfeda4d22014-09-17 13:03:29 -04001966 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04001967 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
1968 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001969 if (error.isError())
1970 {
1971 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07001972 }
1973 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001974
1975 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001976}
1977
Geoff Langb5348332014-09-02 13:16:34 -04001978gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1979 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1980 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001981{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001982 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1983
Geoff Lang5d601382014-07-22 15:14:06 -04001984 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1985 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001986
1987 for (int i = 0; i < depth; i++)
1988 {
1989 int layer = zoffset + i;
1990 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1991
Geoff Langb5348332014-09-02 13:16:34 -04001992 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
1993 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07001994 {
Geoff Langb5348332014-09-02 13:16:34 -04001995 return error;
1996 }
1997
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001998 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1999 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2000 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002001 if (error.isError())
2002 {
2003 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002004 }
2005 }
Geoff Langb5348332014-09-02 13:16:34 -04002006
2007 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002008}
2009
Brandon Jonescef06ff2014-08-05 13:27:48 -07002010void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2011{
2012 UNIMPLEMENTED();
2013}
2014
Brandon Jones142ec422014-07-16 10:31:30 -07002015void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2016{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002017 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2018
Brandon Jones142ec422014-07-16 10:31:30 -07002019 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2020 // the current level we're copying to is defined (with appropriate format, width & height)
2021 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2022
Jamie Madill82bf0c52014-10-03 11:50:53 -04002023 gl::Rectangle sourceRect(x, y, width, height);
2024
Brandon Jones142ec422014-07-16 10:31:30 -07002025 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2026 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04002027 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jones142ec422014-07-16 10:31:30 -07002028 mDirtyImages = true;
2029 }
2030 else
2031 {
2032 ensureRenderTarget();
2033
2034 if (isValidLevel(level))
2035 {
2036 updateStorageLevel(level);
2037
Jamie Madill856d9d42014-09-18 15:08:49 -04002038 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2039 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002040 }
2041 }
2042}
2043
Brandon Jonescef06ff2014-08-05 13:27:48 -07002044void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002045{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002046 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2047
Brandon Jones142ec422014-07-16 10:31:30 -07002048 deleteImages();
2049
2050 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2051 {
2052 GLsizei levelWidth = std::max(1, width >> level);
2053 GLsizei levelHeight = std::max(1, height >> level);
2054
2055 mLayerCounts[level] = (level < levels ? depth : 0);
2056
2057 if (mLayerCounts[level] > 0)
2058 {
2059 // Create new images for this level
2060 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2061
2062 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2063 {
2064 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2065 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2066 levelHeight, 1, true);
2067 }
2068 }
2069 }
2070
2071 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002072
2073 bool renderTarget = IsRenderTargetUsage(mUsage);
2074 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002075 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002076}
2077
Brandon Jones6053a522014-07-25 16:22:09 -07002078void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002079{
Brandon Jones6053a522014-07-25 16:22:09 -07002080 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002081}
2082
Brandon Jones6053a522014-07-25 16:22:09 -07002083void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002084{
Brandon Jones6053a522014-07-25 16:22:09 -07002085 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002086}
2087
Brandon Jones6053a522014-07-25 16:22:09 -07002088
Jamie Madill4aa79e12014-09-29 10:46:14 -04002089void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002090{
2091 int baseWidth = getBaseLevelWidth();
2092 int baseHeight = getBaseLevelHeight();
2093 int baseDepth = getBaseLevelDepth();
2094 GLenum baseFormat = getBaseLevelInternalFormat();
2095
2096 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2097 int levelCount = mipLevels();
2098 for (int level = 1; level < levelCount; level++)
2099 {
2100 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2101 }
Brandon Jones142ec422014-07-16 10:31:30 -07002102}
2103
Jamie Madillac7579c2014-09-17 16:59:33 -04002104unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002105{
Jamie Madillc4833262014-09-18 16:18:26 -04002106 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002107}
2108
Jamie Madillac7579c2014-09-17 16:59:33 -04002109RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002110{
2111 // ensure the underlying texture is created
2112 if (!ensureRenderTarget())
2113 {
2114 return NULL;
2115 }
2116
Jamie Madillac7579c2014-09-17 16:59:33 -04002117 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002118 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002119}
2120
2121void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2122{
2123 // Only initialize the first time this texture is used as a render target or shader resource
2124 if (mTexStorage)
2125 {
2126 return;
2127 }
2128
2129 // do not attempt to create storage for nonexistant data
2130 if (!isLevelComplete(0))
2131 {
2132 return;
2133 }
2134
2135 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2136
2137 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2138 ASSERT(mTexStorage);
2139
2140 // flush image data to the storage
2141 updateStorage();
2142}
2143
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002144TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002145{
2146 GLsizei width = getBaseLevelWidth();
2147 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002148 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002149 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002150
2151 ASSERT(width > 0 && height > 0 && depth > 0);
2152
2153 // use existing storage level count, when previously specified by TexStorage*D
2154 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2155
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002156 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002157}
2158
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002159void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002160{
2161 SafeDelete(mTexStorage);
2162 mTexStorage = newCompleteTexStorage;
2163 mDirtyImages = true;
2164
2165 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2166 ASSERT(!mTexStorage->isManaged());
2167}
2168
2169void TextureD3D_2DArray::updateStorage()
2170{
2171 ASSERT(mTexStorage != NULL);
2172 GLint storageLevels = mTexStorage->getLevelCount();
2173 for (int level = 0; level < storageLevels; level++)
2174 {
2175 if (isLevelComplete(level))
2176 {
2177 updateStorageLevel(level);
2178 }
2179 }
2180}
2181
Brandon Jones142ec422014-07-16 10:31:30 -07002182bool TextureD3D_2DArray::isValidLevel(int level) const
2183{
2184 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2185}
2186
2187bool TextureD3D_2DArray::isLevelComplete(int level) const
2188{
2189 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2190
2191 if (isImmutable())
2192 {
2193 return true;
2194 }
2195
2196 GLsizei width = getBaseLevelWidth();
2197 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002198 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002199
2200 if (width <= 0 || height <= 0 || layers <= 0)
2201 {
2202 return false;
2203 }
2204
2205 if (level == 0)
2206 {
2207 return true;
2208 }
2209
2210 if (getInternalFormat(level) != getInternalFormat(0))
2211 {
2212 return false;
2213 }
2214
2215 if (getWidth(level) != std::max(1, width >> level))
2216 {
2217 return false;
2218 }
2219
2220 if (getHeight(level) != std::max(1, height >> level))
2221 {
2222 return false;
2223 }
2224
Jamie Madill3269bcb2014-09-30 16:33:52 -04002225 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002226 {
2227 return false;
2228 }
2229
2230 return true;
2231}
2232
2233void TextureD3D_2DArray::updateStorageLevel(int level)
2234{
2235 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2236 ASSERT(isLevelComplete(level));
2237
2238 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2239 {
2240 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2241 if (mImageArray[level][layer]->isDirty())
2242 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002243 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2244 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2245 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002246 }
2247 }
2248}
2249
2250void TextureD3D_2DArray::deleteImages()
2251{
2252 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2253 {
2254 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2255 {
2256 delete mImageArray[level][layer];
2257 }
2258 delete[] mImageArray[level];
2259 mImageArray[level] = NULL;
2260 mLayerCounts[level] = 0;
2261 }
2262}
2263
2264void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2265{
2266 // If there currently is a corresponding storage texture image, it has these parameters
2267 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2268 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002269 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002270 const GLenum storageFormat = getBaseLevelInternalFormat();
2271
2272 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2273 {
2274 delete mImageArray[level][layer];
2275 }
2276 delete[] mImageArray[level];
2277 mImageArray[level] = NULL;
2278 mLayerCounts[level] = depth;
2279
2280 if (depth > 0)
2281 {
2282 mImageArray[level] = new ImageD3D*[depth]();
2283
2284 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2285 {
2286 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2287 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2288 }
2289 }
2290
2291 if (mTexStorage)
2292 {
2293 const int storageLevels = mTexStorage->getLevelCount();
2294
2295 if ((level >= storageLevels && storageLevels != 0) ||
2296 width != storageWidth ||
2297 height != storageHeight ||
2298 depth != storageDepth ||
2299 internalformat != storageFormat) // Discard mismatched storage
2300 {
2301 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2302 {
2303 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2304 {
2305 mImageArray[level][layer]->markDirty();
2306 }
2307 }
2308
2309 delete mTexStorage;
2310 mTexStorage = NULL;
2311 mDirtyImages = true;
2312 }
2313 }
2314}
2315
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002316gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002317{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002318 ASSERT(index.hasLayer());
2319 GLint level = index.mipIndex;
2320 GLint layerTarget = index.layerIndex;
2321
Jamie Madill3269bcb2014-09-30 16:33:52 -04002322 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002323 {
2324 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04002325 gl::Error error = image->copyToStorage2DArray(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002326 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002327 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002328 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002329 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002330
2331 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002332 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002333
2334 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002335}
2336
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002337gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2338{
2339 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2340}
2341
Jamie Madillcb83dc12014-09-29 10:46:12 -04002342gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2343{
2344 return gl::ImageIndex::Make2DArray(mip, layer);
2345}
2346
Brandon Jones78b1acd2014-07-15 15:33:07 -07002347}