blob: a4ca35eb3f9aee932a67175e47c7e79bfebc8df1 [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.
Jamie Madill9aca0592014-10-06 16:26:59 -0400105 const uint8_t *pixelData = NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700106
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();
Jamie Madill9aca0592014-10-06 16:26:59 -0400115 pixelData = static_cast<const uint8_t *>(bufferData) + offset;
116 }
117 else
118 {
119 pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700120 }
121
122 if (pixelData != NULL)
123 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400124 gl::Error error(GL_NO_ERROR);
125
126 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
127
128 // TODO(jmadill): Handle compressed internal formats
129 if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
130 {
131 gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
132 error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
133 }
134 else
135 {
136 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
137 }
138
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400139 if (error.isError())
140 {
141 return error;
142 }
143
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700144 mDirtyImages = true;
145 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400146
147 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148}
149
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400150gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
151 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152{
Jamie Madill9aca0592014-10-06 16:26:59 -0400153 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700154
155 // CPU readback & copy where direct GPU copy is not supported
156 if (unpack.pixelBuffer.id() != 0)
157 {
158 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200159 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700160 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
161 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
162 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400163 pixelData = static_cast<const uint8_t *>(bufferData)+offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700164 }
165
166 if (pixelData != NULL)
167 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400168 Image *image = getImage(index);
169 ASSERT(image);
170
Jamie Madill9aca0592014-10-06 16:26:59 -0400171 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
172 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
173
174 // TODO(jmadill): Handle compressed internal formats
175 if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
176 {
177 return mTexStorage->setData(index, region, image->getInternalFormat(),
178 type, unpack, pixelData);
179 }
180
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400181 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
182 type, pixelData);
183 if (error.isError())
184 {
185 return error;
186 }
187
Jamie Madille6b6da02014-10-02 11:03:14 -0400188 error = commitRegion(index, region);
189 if (error.isError())
190 {
191 return error;
192 }
193
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194 mDirtyImages = true;
195 }
196
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400197 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198}
199
Geoff Langb5348332014-09-02 13:16:34 -0400200gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700201{
202 if (pixels != NULL)
203 {
Geoff Langb5348332014-09-02 13:16:34 -0400204 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
205 if (error.isError())
206 {
207 return error;
208 }
209
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700210 mDirtyImages = true;
211 }
Geoff Langb5348332014-09-02 13:16:34 -0400212
213 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700214}
215
Geoff Langb5348332014-09-02 13:16:34 -0400216gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700217 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700218{
219 if (pixels != NULL)
220 {
Geoff Langb5348332014-09-02 13:16:34 -0400221 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
222 if (error.isError())
223 {
224 return error;
225 }
226
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227 mDirtyImages = true;
228 }
229
Geoff Langb5348332014-09-02 13:16:34 -0400230 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
233bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
234{
235 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
236}
237
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400238gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
239 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400241 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700242 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
243 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400244 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700245 }
246
247 // In order to perform the fast copy through the shader, we must have the right format, and be able
248 // to create a render target.
249 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
250
Jacek Cabana5521de2014-10-01 17:23:46 +0200251 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700252
Geoff Langae5122c2014-08-27 14:08:43 -0400253 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
254 if (error.isError())
255 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400256 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400257 }
258
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400259 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700260}
261
262GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
263{
264 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
265 {
266 // Maximum number of levels
267 return gl::log2(std::max(std::max(width, height), depth)) + 1;
268 }
269 else
270 {
271 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
272 return 1;
273 }
274}
275
276int TextureD3D::mipLevels() const
277{
278 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
279}
280
Jamie Madill98553e32014-09-30 16:33:50 -0400281TextureStorage *TextureD3D::getStorage()
282{
283 return mTexStorage;
284}
285
Jamie Madill3269bcb2014-09-30 16:33:52 -0400286Image *TextureD3D::getBaseLevelImage() const
287{
288 return getImage(getImageIndex(0, 0));
289}
290
Jamie Madill4aa79e12014-09-29 10:46:14 -0400291void TextureD3D::generateMipmaps()
292{
Jamie Madill9aca0592014-10-06 16:26:59 -0400293 GLint mipCount = mipLevels();
294
295 if (mipCount == 1)
296 {
297 return; // no-op
298 }
299
300 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400301 initMipmapsImages();
302
303 // We know that all layers have the same dimension, for the texture to be complete
304 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400305
Jamie Madill9aca0592014-10-06 16:26:59 -0400306 // When making mipmaps with the setData workaround enabled, the texture storage has
307 // the image data already. For non-render-target storage, we have to pull it out into
308 // an image layer.
309 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
310 {
311 if (!mTexStorage->isRenderTarget())
312 {
313 // Copy from the storage mip 0 to Image mip 0
314 for (GLint layer = 0; layer < layerCount; ++layer)
315 {
316 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400317
Jamie Madill9aca0592014-10-06 16:26:59 -0400318 Image *image = getImage(srcIndex);
319 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
320 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
321 }
322 }
323 else
324 {
325 updateStorage();
326 }
327 }
328
329 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400330
331 for (GLint layer = 0; layer < layerCount; ++layer)
332 {
333 for (GLint mip = 1; mip < mipCount; ++mip)
334 {
335 ASSERT(getLayerCount(mip) == layerCount);
336
337 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
338 gl::ImageIndex destIndex = getImageIndex(mip, layer);
339
340 if (renderableStorage)
341 {
342 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400343 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400344 }
345 else
346 {
347 // CPU-side mipmapping
348 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
349 }
350 }
351 }
352}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700353
Jamie Madill135570a2014-09-30 16:33:51 -0400354bool TextureD3D::isBaseImageZeroSize() const
355{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400356 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400357
358 if (!baseImage || baseImage->getWidth() <= 0)
359 {
360 return true;
361 }
362
363 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
364 {
365 return true;
366 }
367
368 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
369 {
370 return true;
371 }
372
373 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
374 {
375 return true;
376 }
377
378 return false;
379}
380
381bool TextureD3D::ensureRenderTarget()
382{
383 initializeStorage(true);
384
385 if (!isBaseImageZeroSize())
386 {
387 ASSERT(mTexStorage);
388 if (!mTexStorage->isRenderTarget())
389 {
390 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
391
392 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
393 {
394 delete newRenderTargetStorage;
395 return gl::error(GL_OUT_OF_MEMORY, false);
396 }
397
398 setCompleteTexStorage(newRenderTargetStorage);
399 }
400 }
401
402 return (mTexStorage && mTexStorage->isRenderTarget());
403}
404
Brandon Jones78b1acd2014-07-15 15:33:07 -0700405TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400406 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700407{
408 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
409 {
410 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
411 }
412}
413
414TextureD3D_2D::~TextureD3D_2D()
415{
Austin Kinross69822602014-08-12 15:51:37 -0700416 // Delete the Images before the TextureStorage.
417 // Images might be relying on the TextureStorage for some of their data.
418 // 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 -0700419 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
420 {
421 delete mImageArray[i];
422 }
Austin Kinross69822602014-08-12 15:51:37 -0700423
424 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700425}
426
Brandon Jonescef06ff2014-08-05 13:27:48 -0700427Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700428{
429 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700430 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700431 return mImageArray[level];
432}
433
Jamie Madillfeda4d22014-09-17 13:03:29 -0400434Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
435{
436 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400437 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400438 ASSERT(index.type == GL_TEXTURE_2D);
439 return mImageArray[index.mipIndex];
440}
441
Brandon Jonescef06ff2014-08-05 13:27:48 -0700442GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700443{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700444 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
445 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700446}
447
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700448GLsizei TextureD3D_2D::getWidth(GLint level) const
449{
450 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
451 return mImageArray[level]->getWidth();
452 else
453 return 0;
454}
455
456GLsizei TextureD3D_2D::getHeight(GLint level) const
457{
458 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
459 return mImageArray[level]->getHeight();
460 else
461 return 0;
462}
463
464GLenum TextureD3D_2D::getInternalFormat(GLint level) const
465{
466 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
467 return mImageArray[level]->getInternalFormat();
468 else
469 return GL_NONE;
470}
471
472GLenum TextureD3D_2D::getActualFormat(GLint level) const
473{
474 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
475 return mImageArray[level]->getActualFormat();
476 else
477 return GL_NONE;
478}
479
480bool TextureD3D_2D::isDepth(GLint level) const
481{
Geoff Lang5d601382014-07-22 15:14:06 -0400482 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700483}
484
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400485gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
486 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
487 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700488{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700489 ASSERT(target == GL_TEXTURE_2D && depth == 1);
490
Geoff Lang5d601382014-07-22 15:14:06 -0400491 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
492
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493 bool fastUnpacked = false;
494
Brandon Jonescef06ff2014-08-05 13:27:48 -0700495 redefineImage(level, sizedInternalFormat, width, height);
496
Jamie Madillba6bc952014-10-06 10:56:22 -0400497 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
498
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700499 // Attempt a fast gpu copy of the pixel data to the surface
500 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
501 {
502 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400503 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700504 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
505
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400506 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700507 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400508 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
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
521 if (!fastUnpacked)
522 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400523 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400524 if (error.isError())
525 {
526 return error;
527 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400529
530 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531}
532
Geoff Langb5348332014-09-02 13:16:34 -0400533gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
534 GLsizei width, GLsizei height, GLsizei depth,
535 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700537 ASSERT(target == GL_TEXTURE_2D && depth == 1);
538
539 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
540 redefineImage(level, format, width, height);
541
Geoff Langb5348332014-09-02 13:16:34 -0400542 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543}
544
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400545gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
546 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
547 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700548{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700549 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
550
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551 bool fastUnpacked = false;
552
Jamie Madillac7579c2014-09-17 16:59:33 -0400553 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400554 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
556 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400557 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400559 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400561 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
562 if (error.isError())
563 {
564 return error;
565 }
566
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567 // Ensure we don't overwrite our newly initialized data
568 mImageArray[level]->markClean();
569
570 fastUnpacked = true;
571 }
572 }
573
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400574 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400576 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
577 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700578 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400579
580 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700581}
582
Geoff Langb5348332014-09-02 13:16:34 -0400583gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
584 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
585 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700587 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
588
Geoff Langb5348332014-09-02 13:16:34 -0400589 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
590 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700591 {
Geoff Langb5348332014-09-02 13:16:34 -0400592 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700593 }
Geoff Langb5348332014-09-02 13:16:34 -0400594
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400595 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
596 gl::Box region(xoffset, yoffset, 0, width, height, 1);
597 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700598}
599
Brandon Jonescef06ff2014-08-05 13:27:48 -0700600void 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 -0700601{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700602 ASSERT(target == GL_TEXTURE_2D);
603
604 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
605 redefineImage(level, sizedInternalFormat, width, height);
606
Jamie Madill82bf0c52014-10-03 11:50:53 -0400607 gl::Rectangle sourceRect(x, y, width, height);
608
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700609 if (!mImageArray[level]->isRenderableFormat())
610 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400611 mImageArray[level]->copy(0, 0, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700612 mDirtyImages = true;
613 }
614 else
615 {
616 ensureRenderTarget();
617 mImageArray[level]->markClean();
618
619 if (width != 0 && height != 0 && isValidLevel(level))
620 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400621 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622 }
623 }
624}
625
626void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
627{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700628 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
629
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
631 // the current level we're copying to is defined (with appropriate format, width & height)
632 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
633
Jamie Madill82bf0c52014-10-03 11:50:53 -0400634 gl::Rectangle sourceRect(x, y, width, height);
635
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
637 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400638 mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639 mDirtyImages = true;
640 }
641 else
642 {
643 ensureRenderTarget();
644
645 if (isValidLevel(level))
646 {
647 updateStorageLevel(level);
648
Jamie Madill856d9d42014-09-18 15:08:49 -0400649 mRenderer->copyImage2D(source, sourceRect,
650 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
651 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652 }
653 }
654}
655
Brandon Jonescef06ff2014-08-05 13:27:48 -0700656void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700657{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700658 ASSERT(target == GL_TEXTURE_2D && depth == 1);
659
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700660 for (int level = 0; level < levels; level++)
661 {
662 GLsizei levelWidth = std::max(1, width >> level);
663 GLsizei levelHeight = std::max(1, height >> level);
664 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
665 }
666
667 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
668 {
669 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
670 }
671
672 mImmutable = true;
673
Jamie Madillc4833262014-09-18 16:18:26 -0400674 bool renderTarget = IsRenderTargetUsage(mUsage);
675 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400676 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677}
678
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679void TextureD3D_2D::bindTexImage(egl::Surface *surface)
680{
681 GLenum internalformat = surface->getFormat();
682
683 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
684
685 if (mTexStorage)
686 {
687 SafeDelete(mTexStorage);
688 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400689
690 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691
692 mDirtyImages = true;
693}
694
695void TextureD3D_2D::releaseTexImage()
696{
697 if (mTexStorage)
698 {
699 SafeDelete(mTexStorage);
700 }
701
702 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
703 {
704 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
705 }
706}
707
Jamie Madill4aa79e12014-09-29 10:46:14 -0400708void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700709{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700710 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700711 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700712 for (int level = 1; level < levelCount; level++)
713 {
714 redefineImage(level, getBaseLevelInternalFormat(),
715 std::max(getBaseLevelWidth() >> level, 1),
716 std::max(getBaseLevelHeight() >> level, 1));
717 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700718}
719
Jamie Madillac7579c2014-09-17 16:59:33 -0400720unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700721{
Jamie Madillac7579c2014-09-17 16:59:33 -0400722 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400723 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700724}
725
Jamie Madillac7579c2014-09-17 16:59:33 -0400726RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700727{
Jamie Madillac7579c2014-09-17 16:59:33 -0400728 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700729
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700730 // ensure the underlying texture is created
731 if (!ensureRenderTarget())
732 {
733 return NULL;
734 }
735
Jamie Madillac7579c2014-09-17 16:59:33 -0400736 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400737 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700738}
739
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700740bool TextureD3D_2D::isValidLevel(int level) const
741{
742 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
743}
744
745bool TextureD3D_2D::isLevelComplete(int level) const
746{
747 if (isImmutable())
748 {
749 return true;
750 }
751
Brandon Jones78b1acd2014-07-15 15:33:07 -0700752 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700753
754 GLsizei width = baseImage->getWidth();
755 GLsizei height = baseImage->getHeight();
756
757 if (width <= 0 || height <= 0)
758 {
759 return false;
760 }
761
762 // The base image level is complete if the width and height are positive
763 if (level == 0)
764 {
765 return true;
766 }
767
768 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700769 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770
771 if (image->getInternalFormat() != baseImage->getInternalFormat())
772 {
773 return false;
774 }
775
776 if (image->getWidth() != std::max(1, width >> level))
777 {
778 return false;
779 }
780
781 if (image->getHeight() != std::max(1, height >> level))
782 {
783 return false;
784 }
785
786 return true;
787}
788
789// Constructs a native texture resource from the texture images
790void TextureD3D_2D::initializeStorage(bool renderTarget)
791{
792 // Only initialize the first time this texture is used as a render target or shader resource
793 if (mTexStorage)
794 {
795 return;
796 }
797
798 // do not attempt to create storage for nonexistant data
799 if (!isLevelComplete(0))
800 {
801 return;
802 }
803
804 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
805
806 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
807 ASSERT(mTexStorage);
808
809 // flush image data to the storage
810 updateStorage();
811}
812
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400813TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700814{
815 GLsizei width = getBaseLevelWidth();
816 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400817 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818
819 ASSERT(width > 0 && height > 0);
820
821 // use existing storage level count, when previously specified by TexStorage*D
822 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
823
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400824 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700825}
826
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400827void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700828{
829 SafeDelete(mTexStorage);
830 mTexStorage = newCompleteTexStorage;
831
832 if (mTexStorage && mTexStorage->isManaged())
833 {
834 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
835 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400836 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700837 }
838 }
839
840 mDirtyImages = true;
841}
842
843void TextureD3D_2D::updateStorage()
844{
845 ASSERT(mTexStorage != NULL);
846 GLint storageLevels = mTexStorage->getLevelCount();
847 for (int level = 0; level < storageLevels; level++)
848 {
849 if (mImageArray[level]->isDirty() && isLevelComplete(level))
850 {
851 updateStorageLevel(level);
852 }
853 }
854}
855
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700856void TextureD3D_2D::updateStorageLevel(int level)
857{
858 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
859 ASSERT(isLevelComplete(level));
860
861 if (mImageArray[level]->isDirty())
862 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400863 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
864 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
865 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866 }
867}
868
869void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
870{
871 // If there currently is a corresponding storage texture image, it has these parameters
872 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
873 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
874 const GLenum storageFormat = getBaseLevelInternalFormat();
875
876 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
877
878 if (mTexStorage)
879 {
880 const int storageLevels = mTexStorage->getLevelCount();
881
882 if ((level >= storageLevels && storageLevels != 0) ||
883 width != storageWidth ||
884 height != storageHeight ||
885 internalformat != storageFormat) // Discard mismatched storage
886 {
887 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
888 {
889 mImageArray[i]->markDirty();
890 }
891
892 SafeDelete(mTexStorage);
893 mDirtyImages = true;
894 }
895 }
896}
897
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400898gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700899{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400900 ASSERT(!index.hasLayer());
901 GLint level = index.mipIndex;
902
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700903 if (isValidLevel(level))
904 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700905 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -0400906 gl::Error error = image->copyToStorage2D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400907 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700908 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400909 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700910 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400911
912 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700913 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400914
915 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700916}
917
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400918gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
919{
920 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
921}
Brandon Jones0511e802014-07-14 16:27:26 -0700922
Jamie Madillcb83dc12014-09-29 10:46:12 -0400923gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
924{
925 // "layer" does not apply to 2D Textures.
926 return gl::ImageIndex::Make2D(mip);
927}
928
Brandon Jones78b1acd2014-07-15 15:33:07 -0700929TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400930 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700931{
932 for (int i = 0; i < 6; i++)
933 {
934 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
935 {
936 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
937 }
938 }
939}
940
941TextureD3D_Cube::~TextureD3D_Cube()
942{
Austin Kinross69822602014-08-12 15:51:37 -0700943 // Delete the Images before the TextureStorage.
944 // Images might be relying on the TextureStorage for some of their data.
945 // 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 -0700946 for (int i = 0; i < 6; i++)
947 {
948 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
949 {
950 SafeDelete(mImageArray[i][j]);
951 }
952 }
Austin Kinross69822602014-08-12 15:51:37 -0700953
954 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700955}
956
Brandon Jonescef06ff2014-08-05 13:27:48 -0700957Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700958{
959 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700960 ASSERT(layer < 6);
961 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700962}
963
Jamie Madillfeda4d22014-09-17 13:03:29 -0400964Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
965{
966 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
967 ASSERT(index.layerIndex < 6);
968 return mImageArray[index.layerIndex][index.mipIndex];
969}
970
Brandon Jonescef06ff2014-08-05 13:27:48 -0700971GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700972{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700973 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
974 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700975}
976
Brandon Jonescef06ff2014-08-05 13:27:48 -0700977GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700978{
979 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700980 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700981 else
982 return GL_NONE;
983}
984
Brandon Jonescef06ff2014-08-05 13:27:48 -0700985bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700986{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700987 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700988}
989
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400990gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
991 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
992 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700993{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700994 ASSERT(depth == 1);
995
Geoff Lang5d601382014-07-22 15:14:06 -0400996 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -0400997 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -0700998
Jamie Madillba6bc952014-10-06 10:56:22 -0400999 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001000
Jamie Madillba6bc952014-10-06 10:56:22 -04001001 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001002}
1003
Geoff Langb5348332014-09-02 13:16:34 -04001004gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1005 GLsizei width, GLsizei height, GLsizei depth,
1006 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001007{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001008 ASSERT(depth == 1);
1009
Brandon Jones0511e802014-07-14 16:27:26 -07001010 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001011 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1012
Brandon Jones0511e802014-07-14 16:27:26 -07001013 redefineImage(faceIndex, level, format, width, height);
1014
Geoff Langb5348332014-09-02 13:16:34 -04001015 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001016}
1017
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001018gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1019 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1020 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001021{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001022 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001023 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001024 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001025}
1026
Geoff Langb5348332014-09-02 13:16:34 -04001027gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1028 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1029 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001030{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001031 ASSERT(depth == 1 && zoffset == 0);
1032
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001033 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001034
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001035 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 -04001036 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001037 {
Geoff Langb5348332014-09-02 13:16:34 -04001038 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001039 }
Geoff Langb5348332014-09-02 13:16:34 -04001040
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001041 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1042 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001043}
1044
1045void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1046{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001047 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001048 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1049
Brandon Jones0511e802014-07-14 16:27:26 -07001050 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1051
Jamie Madill82bf0c52014-10-03 11:50:53 -04001052 gl::Rectangle sourceRect(x, y, width, height);
1053
Brandon Jones0511e802014-07-14 16:27:26 -07001054 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1055 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001056 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001057 mDirtyImages = true;
1058 }
1059 else
1060 {
1061 ensureRenderTarget();
1062 mImageArray[faceIndex][level]->markClean();
1063
1064 ASSERT(width == height);
1065
1066 if (width > 0 && isValidFaceLevel(faceIndex, level))
1067 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001068 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001069 }
1070 }
1071}
1072
1073void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1074{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001075 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001076
1077 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1078 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1079 // rely on the "getBaseLevel*" methods reliably otherwise.
1080 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1081
Jamie Madill82bf0c52014-10-03 11:50:53 -04001082 gl::Rectangle sourceRect(x, y, width, height);
1083
Brandon Jones0511e802014-07-14 16:27:26 -07001084 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1085 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001086 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001087 mDirtyImages = true;
1088 }
1089 else
1090 {
1091 ensureRenderTarget();
1092
1093 if (isValidFaceLevel(faceIndex, level))
1094 {
1095 updateStorageFaceLevel(faceIndex, level);
1096
Jamie Madill856d9d42014-09-18 15:08:49 -04001097 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1098 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001099 }
1100 }
1101}
1102
Brandon Jonescef06ff2014-08-05 13:27:48 -07001103void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001104{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001105 ASSERT(width == height);
1106 ASSERT(depth == 1);
1107
Brandon Jones0511e802014-07-14 16:27:26 -07001108 for (int level = 0; level < levels; level++)
1109 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001110 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001111 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1112 {
1113 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1114 }
1115 }
1116
1117 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1118 {
1119 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1120 {
1121 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1122 }
1123 }
1124
1125 mImmutable = true;
1126
Jamie Madillc4833262014-09-18 16:18:26 -04001127 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001128 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1129 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001130}
1131
Brandon Jones0511e802014-07-14 16:27:26 -07001132// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1133bool TextureD3D_Cube::isCubeComplete() const
1134{
1135 int baseWidth = getBaseLevelWidth();
1136 int baseHeight = getBaseLevelHeight();
1137 GLenum baseFormat = getBaseLevelInternalFormat();
1138
1139 if (baseWidth <= 0 || baseWidth != baseHeight)
1140 {
1141 return false;
1142 }
1143
1144 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1145 {
1146 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1147
1148 if (faceBaseImage.getWidth() != baseWidth ||
1149 faceBaseImage.getHeight() != baseHeight ||
1150 faceBaseImage.getInternalFormat() != baseFormat )
1151 {
1152 return false;
1153 }
1154 }
1155
1156 return true;
1157}
1158
Brandon Jones6053a522014-07-25 16:22:09 -07001159void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1160{
1161 UNREACHABLE();
1162}
1163
1164void TextureD3D_Cube::releaseTexImage()
1165{
1166 UNREACHABLE();
1167}
1168
1169
Jamie Madill4aa79e12014-09-29 10:46:14 -04001170void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001171{
1172 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1173 int levelCount = mipLevels();
1174 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1175 {
1176 for (int level = 1; level < levelCount; level++)
1177 {
1178 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1179 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1180 }
1181 }
Brandon Jones0511e802014-07-14 16:27:26 -07001182}
1183
Jamie Madillac7579c2014-09-17 16:59:33 -04001184unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001185{
Jamie Madillc4833262014-09-18 16:18:26 -04001186 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001187}
1188
Jamie Madillac7579c2014-09-17 16:59:33 -04001189RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001190{
Jamie Madillac7579c2014-09-17 16:59:33 -04001191 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001192
1193 // ensure the underlying texture is created
1194 if (!ensureRenderTarget())
1195 {
1196 return NULL;
1197 }
1198
Jamie Madillac7579c2014-09-17 16:59:33 -04001199 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001200 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001201}
1202
Brandon Jones0511e802014-07-14 16:27:26 -07001203void TextureD3D_Cube::initializeStorage(bool renderTarget)
1204{
1205 // Only initialize the first time this texture is used as a render target or shader resource
1206 if (mTexStorage)
1207 {
1208 return;
1209 }
1210
1211 // do not attempt to create storage for nonexistant data
1212 if (!isFaceLevelComplete(0, 0))
1213 {
1214 return;
1215 }
1216
1217 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1218
1219 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1220 ASSERT(mTexStorage);
1221
1222 // flush image data to the storage
1223 updateStorage();
1224}
1225
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001226TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001227{
1228 GLsizei size = getBaseLevelWidth();
1229
1230 ASSERT(size > 0);
1231
1232 // use existing storage level count, when previously specified by TexStorage*D
1233 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1234
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001235 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001236}
1237
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001238void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001239{
1240 SafeDelete(mTexStorage);
1241 mTexStorage = newCompleteTexStorage;
1242
1243 if (mTexStorage && mTexStorage->isManaged())
1244 {
1245 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1246 {
1247 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1248 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001249 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001250 }
1251 }
1252 }
1253
1254 mDirtyImages = true;
1255}
1256
1257void TextureD3D_Cube::updateStorage()
1258{
1259 ASSERT(mTexStorage != NULL);
1260 GLint storageLevels = mTexStorage->getLevelCount();
1261 for (int face = 0; face < 6; face++)
1262 {
1263 for (int level = 0; level < storageLevels; level++)
1264 {
1265 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1266 {
1267 updateStorageFaceLevel(face, level);
1268 }
1269 }
1270 }
1271}
1272
Brandon Jones0511e802014-07-14 16:27:26 -07001273bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1274{
1275 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1276}
1277
Brandon Jones0511e802014-07-14 16:27:26 -07001278bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1279{
1280 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1281
1282 if (isImmutable())
1283 {
1284 return true;
1285 }
1286
1287 int baseSize = getBaseLevelWidth();
1288
1289 if (baseSize <= 0)
1290 {
1291 return false;
1292 }
1293
1294 // "isCubeComplete" checks for base level completeness and we must call that
1295 // to determine if any face at level 0 is complete. We omit that check here
1296 // to avoid re-checking cube-completeness for every face at level 0.
1297 if (level == 0)
1298 {
1299 return true;
1300 }
1301
1302 // Check that non-zero levels are consistent with the base level.
1303 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1304
1305 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1306 {
1307 return false;
1308 }
1309
1310 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1311 {
1312 return false;
1313 }
1314
1315 return true;
1316}
1317
1318void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1319{
1320 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1321 ImageD3D *image = mImageArray[faceIndex][level];
1322
1323 if (image->isDirty())
1324 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001325 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1326 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1327 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1328 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001329 }
1330}
1331
1332void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1333{
1334 // If there currently is a corresponding storage texture image, it has these parameters
1335 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1336 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1337 const GLenum storageFormat = getBaseLevelInternalFormat();
1338
1339 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1340
1341 if (mTexStorage)
1342 {
1343 const int storageLevels = mTexStorage->getLevelCount();
1344
1345 if ((level >= storageLevels && storageLevels != 0) ||
1346 width != storageWidth ||
1347 height != storageHeight ||
1348 internalformat != storageFormat) // Discard mismatched storage
1349 {
1350 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1351 {
1352 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1353 {
1354 mImageArray[faceIndex][level]->markDirty();
1355 }
1356 }
1357
1358 SafeDelete(mTexStorage);
1359
1360 mDirtyImages = true;
1361 }
1362 }
1363}
1364
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001365gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001366{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001367 ASSERT(index.hasLayer());
1368
1369 GLint level = index.mipIndex;
1370 int faceIndex = static_cast<int>(index.layerIndex);
1371
Brandon Jones0511e802014-07-14 16:27:26 -07001372 if (isValidFaceLevel(faceIndex, level))
1373 {
1374 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001375 gl::Error error = image->copyToStorageCube(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001376 if (error.isError())
1377 {
1378 return error;
1379 }
1380
1381 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001382 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001383
1384 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001385}
1386
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001387gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1388{
1389 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1390}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001391
Jamie Madillcb83dc12014-09-29 10:46:12 -04001392gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1393{
1394 // The "layer" of the image index corresponds to the cube face
1395 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1396}
1397
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001399 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001400{
1401 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1402 {
1403 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1404 }
1405}
1406
1407TextureD3D_3D::~TextureD3D_3D()
1408{
Austin Kinross69822602014-08-12 15:51:37 -07001409 // Delete the Images before the TextureStorage.
1410 // Images might be relying on the TextureStorage for some of their data.
1411 // 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 -07001412 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1413 {
1414 delete mImageArray[i];
1415 }
Austin Kinross69822602014-08-12 15:51:37 -07001416
1417 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001418}
1419
Brandon Jonescef06ff2014-08-05 13:27:48 -07001420Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001421{
1422 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001423 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001424 return mImageArray[level];
1425}
1426
Jamie Madillfeda4d22014-09-17 13:03:29 -04001427Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1428{
1429 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001430 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001431 ASSERT(index.type == GL_TEXTURE_3D);
1432 return mImageArray[index.mipIndex];
1433}
1434
Brandon Jonescef06ff2014-08-05 13:27:48 -07001435GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001436{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001437 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1438 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001439}
1440
Brandon Jones78b1acd2014-07-15 15:33:07 -07001441GLsizei TextureD3D_3D::getWidth(GLint level) const
1442{
1443 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1444 return mImageArray[level]->getWidth();
1445 else
1446 return 0;
1447}
1448
1449GLsizei TextureD3D_3D::getHeight(GLint level) const
1450{
1451 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1452 return mImageArray[level]->getHeight();
1453 else
1454 return 0;
1455}
1456
1457GLsizei TextureD3D_3D::getDepth(GLint level) const
1458{
1459 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1460 return mImageArray[level]->getDepth();
1461 else
1462 return 0;
1463}
1464
1465GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1466{
1467 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1468 return mImageArray[level]->getInternalFormat();
1469 else
1470 return GL_NONE;
1471}
1472
1473bool TextureD3D_3D::isDepth(GLint level) const
1474{
Geoff Lang5d601382014-07-22 15:14:06 -04001475 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001476}
1477
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001478gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1479 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1480 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001481{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001482 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001483 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1484
Brandon Jones78b1acd2014-07-15 15:33:07 -07001485 redefineImage(level, sizedInternalFormat, width, height, depth);
1486
1487 bool fastUnpacked = false;
1488
Jamie Madillba6bc952014-10-06 10:56:22 -04001489 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1490
Brandon Jones78b1acd2014-07-15 15:33:07 -07001491 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1492 if (isFastUnpackable(unpack, sizedInternalFormat))
1493 {
1494 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001495 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001496 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1497
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001498 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001499 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001500 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1501 if (error.isError())
1502 {
1503 return error;
1504 }
1505
Brandon Jones78b1acd2014-07-15 15:33:07 -07001506 // Ensure we don't overwrite our newly initialized data
1507 mImageArray[level]->markClean();
1508
1509 fastUnpacked = true;
1510 }
1511 }
1512
1513 if (!fastUnpacked)
1514 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001515 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001516 if (error.isError())
1517 {
1518 return error;
1519 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001520 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001521
1522 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523}
1524
Geoff Langb5348332014-09-02 13:16:34 -04001525gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1526 GLsizei width, GLsizei height,GLsizei depth,
1527 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001528{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001529 ASSERT(target == GL_TEXTURE_3D);
1530
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1532 redefineImage(level, format, width, height, depth);
1533
Geoff Langb5348332014-09-02 13:16:34 -04001534 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535}
1536
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001537gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1538 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1539 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001541 ASSERT(target == GL_TEXTURE_3D);
1542
Brandon Jones78b1acd2014-07-15 15:33:07 -07001543 bool fastUnpacked = false;
1544
Jamie Madillac7579c2014-09-17 16:59:33 -04001545 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1546
Brandon Jones78b1acd2014-07-15 15:33:07 -07001547 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1548 if (isFastUnpackable(unpack, getInternalFormat(level)))
1549 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001550 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001551
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001552 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001553 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001554 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001555 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1556 if (error.isError())
1557 {
1558 return error;
1559 }
1560
Brandon Jones78b1acd2014-07-15 15:33:07 -07001561 // Ensure we don't overwrite our newly initialized data
1562 mImageArray[level]->markClean();
1563
1564 fastUnpacked = true;
1565 }
1566 }
1567
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001568 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001569 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001570 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1571 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001572 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001573
1574 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001575}
1576
Geoff Langb5348332014-09-02 13:16:34 -04001577gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1578 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1579 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001580{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001581 ASSERT(target == GL_TEXTURE_3D);
1582
Geoff Langb5348332014-09-02 13:16:34 -04001583 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1584 format, imageSize, pixels, mImageArray[level]);
1585 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001586 {
Geoff Langb5348332014-09-02 13:16:34 -04001587 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001588 }
Geoff Langb5348332014-09-02 13:16:34 -04001589
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001590 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1591 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1592 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001593}
1594
Brandon Jonescef06ff2014-08-05 13:27:48 -07001595void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1596{
1597 UNIMPLEMENTED();
1598}
1599
Brandon Jones78b1acd2014-07-15 15:33:07 -07001600void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1601{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001602 ASSERT(target == GL_TEXTURE_3D);
1603
Brandon Jones78b1acd2014-07-15 15:33:07 -07001604 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1605 // the current level we're copying to is defined (with appropriate format, width & height)
1606 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1607
Jamie Madill82bf0c52014-10-03 11:50:53 -04001608 gl::Rectangle sourceRect(x, y, width, height);
1609
Brandon Jones78b1acd2014-07-15 15:33:07 -07001610 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1611 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001612 mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001613 mDirtyImages = true;
1614 }
1615 else
1616 {
1617 ensureRenderTarget();
1618
1619 if (isValidLevel(level))
1620 {
1621 updateStorageLevel(level);
1622
Jamie Madill856d9d42014-09-18 15:08:49 -04001623 mRenderer->copyImage3D(source, sourceRect,
1624 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1625 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626 }
1627 }
1628}
1629
Brandon Jonescef06ff2014-08-05 13:27:48 -07001630void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001631{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001632 ASSERT(target == GL_TEXTURE_3D);
1633
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634 for (int level = 0; level < levels; level++)
1635 {
1636 GLsizei levelWidth = std::max(1, width >> level);
1637 GLsizei levelHeight = std::max(1, height >> level);
1638 GLsizei levelDepth = std::max(1, depth >> level);
1639 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1640 }
1641
1642 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1643 {
1644 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1645 }
1646
1647 mImmutable = true;
1648
Jamie Madillc4833262014-09-18 16:18:26 -04001649 bool renderTarget = IsRenderTargetUsage(mUsage);
1650 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001651 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652}
1653
Brandon Jones6053a522014-07-25 16:22:09 -07001654void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001655{
Brandon Jones6053a522014-07-25 16:22:09 -07001656 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657}
1658
Brandon Jones6053a522014-07-25 16:22:09 -07001659void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001660{
Brandon Jones6053a522014-07-25 16:22:09 -07001661 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001662}
1663
Brandon Jones6053a522014-07-25 16:22:09 -07001664
Jamie Madill4aa79e12014-09-29 10:46:14 -04001665void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001666{
1667 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1668 int levelCount = mipLevels();
1669 for (int level = 1; level < levelCount; level++)
1670 {
1671 redefineImage(level, getBaseLevelInternalFormat(),
1672 std::max(getBaseLevelWidth() >> level, 1),
1673 std::max(getBaseLevelHeight() >> level, 1),
1674 std::max(getBaseLevelDepth() >> level, 1));
1675 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001676}
1677
Jamie Madillac7579c2014-09-17 16:59:33 -04001678unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001679{
Jamie Madillc4833262014-09-18 16:18:26 -04001680 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001681}
1682
Jamie Madillac7579c2014-09-17 16:59:33 -04001683RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001684{
1685 // ensure the underlying texture is created
1686 if (!ensureRenderTarget())
1687 {
1688 return NULL;
1689 }
1690
Jamie Madillac7579c2014-09-17 16:59:33 -04001691 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001692 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001693 updateStorage();
1694 }
1695 else
1696 {
1697 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001698 }
1699
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001700 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001701}
1702
1703void TextureD3D_3D::initializeStorage(bool renderTarget)
1704{
1705 // Only initialize the first time this texture is used as a render target or shader resource
1706 if (mTexStorage)
1707 {
1708 return;
1709 }
1710
1711 // do not attempt to create storage for nonexistant data
1712 if (!isLevelComplete(0))
1713 {
1714 return;
1715 }
1716
1717 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1718
1719 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1720 ASSERT(mTexStorage);
1721
1722 // flush image data to the storage
1723 updateStorage();
1724}
1725
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001726TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001727{
1728 GLsizei width = getBaseLevelWidth();
1729 GLsizei height = getBaseLevelHeight();
1730 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001731 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001732
1733 ASSERT(width > 0 && height > 0 && depth > 0);
1734
1735 // use existing storage level count, when previously specified by TexStorage*D
1736 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1737
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001738 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739}
1740
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001741void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001742{
1743 SafeDelete(mTexStorage);
1744 mTexStorage = newCompleteTexStorage;
1745 mDirtyImages = true;
1746
1747 // We do not support managed 3D storage, as that is D3D9/ES2-only
1748 ASSERT(!mTexStorage->isManaged());
1749}
1750
1751void TextureD3D_3D::updateStorage()
1752{
1753 ASSERT(mTexStorage != NULL);
1754 GLint storageLevels = mTexStorage->getLevelCount();
1755 for (int level = 0; level < storageLevels; level++)
1756 {
1757 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1758 {
1759 updateStorageLevel(level);
1760 }
1761 }
1762}
1763
Brandon Jones78b1acd2014-07-15 15:33:07 -07001764bool TextureD3D_3D::isValidLevel(int level) const
1765{
1766 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1767}
1768
1769bool TextureD3D_3D::isLevelComplete(int level) const
1770{
1771 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1772
1773 if (isImmutable())
1774 {
1775 return true;
1776 }
1777
1778 GLsizei width = getBaseLevelWidth();
1779 GLsizei height = getBaseLevelHeight();
1780 GLsizei depth = getBaseLevelDepth();
1781
1782 if (width <= 0 || height <= 0 || depth <= 0)
1783 {
1784 return false;
1785 }
1786
1787 if (level == 0)
1788 {
1789 return true;
1790 }
1791
1792 ImageD3D *levelImage = mImageArray[level];
1793
1794 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1795 {
1796 return false;
1797 }
1798
1799 if (levelImage->getWidth() != std::max(1, width >> level))
1800 {
1801 return false;
1802 }
1803
1804 if (levelImage->getHeight() != std::max(1, height >> level))
1805 {
1806 return false;
1807 }
1808
1809 if (levelImage->getDepth() != std::max(1, depth >> level))
1810 {
1811 return false;
1812 }
1813
1814 return true;
1815}
1816
1817void TextureD3D_3D::updateStorageLevel(int level)
1818{
1819 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1820 ASSERT(isLevelComplete(level));
1821
1822 if (mImageArray[level]->isDirty())
1823 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001824 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1825 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1826 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001827 }
1828}
1829
1830void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1831{
1832 // If there currently is a corresponding storage texture image, it has these parameters
1833 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1834 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1835 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1836 const GLenum storageFormat = getBaseLevelInternalFormat();
1837
1838 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1839
1840 if (mTexStorage)
1841 {
1842 const int storageLevels = mTexStorage->getLevelCount();
1843
1844 if ((level >= storageLevels && storageLevels != 0) ||
1845 width != storageWidth ||
1846 height != storageHeight ||
1847 depth != storageDepth ||
1848 internalformat != storageFormat) // Discard mismatched storage
1849 {
1850 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1851 {
1852 mImageArray[i]->markDirty();
1853 }
1854
1855 SafeDelete(mTexStorage);
1856 mDirtyImages = true;
1857 }
1858 }
1859}
1860
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001861gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001862{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001863 ASSERT(!index.hasLayer());
1864 GLint level = index.mipIndex;
1865
Brandon Jones78b1acd2014-07-15 15:33:07 -07001866 if (isValidLevel(level))
1867 {
1868 ImageD3D *image = mImageArray[level];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04001869 gl::Error error = image->copyToStorage3D(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001870 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001871 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001872 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001873 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001874
1875 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001876 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001877
1878 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001879}
1880
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001881gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1882{
1883 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1884 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1885}
Brandon Jones142ec422014-07-16 10:31:30 -07001886
Jamie Madillcb83dc12014-09-29 10:46:12 -04001887gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1888{
1889 // The "layer" here does not apply to 3D images. We use one Image per mip.
1890 return gl::ImageIndex::Make3D(mip);
1891}
1892
Brandon Jones142ec422014-07-16 10:31:30 -07001893TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001894 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001895{
1896 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1897 {
1898 mLayerCounts[level] = 0;
1899 mImageArray[level] = NULL;
1900 }
1901}
1902
1903TextureD3D_2DArray::~TextureD3D_2DArray()
1904{
Austin Kinross69822602014-08-12 15:51:37 -07001905 // Delete the Images before the TextureStorage.
1906 // Images might be relying on the TextureStorage for some of their data.
1907 // 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 -07001908 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001909 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001910}
1911
Brandon Jones142ec422014-07-16 10:31:30 -07001912Image *TextureD3D_2DArray::getImage(int level, int layer) const
1913{
1914 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1915 ASSERT(layer < mLayerCounts[level]);
1916 return mImageArray[level][layer];
1917}
1918
Jamie Madillfeda4d22014-09-17 13:03:29 -04001919Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1920{
1921 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1922 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1923 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1924 return mImageArray[index.mipIndex][index.layerIndex];
1925}
1926
Brandon Jones142ec422014-07-16 10:31:30 -07001927GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1928{
1929 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1930 return mLayerCounts[level];
1931}
1932
Brandon Jones142ec422014-07-16 10:31:30 -07001933GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1934{
1935 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1936}
1937
1938GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1939{
1940 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1941}
1942
Brandon Jones142ec422014-07-16 10:31:30 -07001943GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1944{
1945 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1946}
1947
1948bool TextureD3D_2DArray::isDepth(GLint level) const
1949{
Geoff Lang5d601382014-07-22 15:14:06 -04001950 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001951}
1952
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001953gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1954 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1955 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001956{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001957 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1958
Geoff Lang5d601382014-07-22 15:14:06 -04001959 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1960
Brandon Jones142ec422014-07-16 10:31:30 -07001961 redefineImage(level, sizedInternalFormat, width, height, depth);
1962
Geoff Lang5d601382014-07-22 15:14:06 -04001963 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1964 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001965
1966 for (int i = 0; i < depth; i++)
1967 {
1968 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04001969 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
1970 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001971 if (error.isError())
1972 {
1973 return error;
1974 }
Brandon Jones142ec422014-07-16 10:31:30 -07001975 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001976
1977 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001978}
1979
Geoff Langb5348332014-09-02 13:16:34 -04001980gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1981 GLsizei width, GLsizei height, GLsizei depth,
1982 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001983{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001984 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1985
Brandon Jones142ec422014-07-16 10:31:30 -07001986 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1987 redefineImage(level, format, width, height, depth);
1988
Geoff Lang5d601382014-07-22 15:14:06 -04001989 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1990 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001991
1992 for (int i = 0; i < depth; i++)
1993 {
1994 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001995 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1996 if (error.isError())
1997 {
1998 return error;
1999 }
Brandon Jones142ec422014-07-16 10:31:30 -07002000 }
Geoff Langb5348332014-09-02 13:16:34 -04002001
2002 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002003}
2004
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002005gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2006 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2007 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002008{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002009 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2010
Geoff Lang5d601382014-07-22 15:14:06 -04002011 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2012 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002013
2014 for (int i = 0; i < depth; i++)
2015 {
2016 int layer = zoffset + i;
2017 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2018
Jamie Madillfeda4d22014-09-17 13:03:29 -04002019 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002020 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2021 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002022 if (error.isError())
2023 {
2024 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002025 }
2026 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002027
2028 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002029}
2030
Geoff Langb5348332014-09-02 13:16:34 -04002031gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2032 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2033 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002034{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002035 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2036
Geoff Lang5d601382014-07-22 15:14:06 -04002037 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2038 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002039
2040 for (int i = 0; i < depth; i++)
2041 {
2042 int layer = zoffset + i;
2043 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2044
Geoff Langb5348332014-09-02 13:16:34 -04002045 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2046 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002047 {
Geoff Langb5348332014-09-02 13:16:34 -04002048 return error;
2049 }
2050
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002051 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2052 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2053 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002054 if (error.isError())
2055 {
2056 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002057 }
2058 }
Geoff Langb5348332014-09-02 13:16:34 -04002059
2060 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002061}
2062
Brandon Jonescef06ff2014-08-05 13:27:48 -07002063void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2064{
2065 UNIMPLEMENTED();
2066}
2067
Brandon Jones142ec422014-07-16 10:31:30 -07002068void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2069{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002070 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2071
Brandon Jones142ec422014-07-16 10:31:30 -07002072 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2073 // the current level we're copying to is defined (with appropriate format, width & height)
2074 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2075
Jamie Madill82bf0c52014-10-03 11:50:53 -04002076 gl::Rectangle sourceRect(x, y, width, height);
2077
Brandon Jones142ec422014-07-16 10:31:30 -07002078 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2079 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04002080 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jones142ec422014-07-16 10:31:30 -07002081 mDirtyImages = true;
2082 }
2083 else
2084 {
2085 ensureRenderTarget();
2086
2087 if (isValidLevel(level))
2088 {
2089 updateStorageLevel(level);
2090
Jamie Madill856d9d42014-09-18 15:08:49 -04002091 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2092 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002093 }
2094 }
2095}
2096
Brandon Jonescef06ff2014-08-05 13:27:48 -07002097void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002098{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002099 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2100
Brandon Jones142ec422014-07-16 10:31:30 -07002101 deleteImages();
2102
2103 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2104 {
2105 GLsizei levelWidth = std::max(1, width >> level);
2106 GLsizei levelHeight = std::max(1, height >> level);
2107
2108 mLayerCounts[level] = (level < levels ? depth : 0);
2109
2110 if (mLayerCounts[level] > 0)
2111 {
2112 // Create new images for this level
2113 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2114
2115 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2116 {
2117 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2118 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2119 levelHeight, 1, true);
2120 }
2121 }
2122 }
2123
2124 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002125
2126 bool renderTarget = IsRenderTargetUsage(mUsage);
2127 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002128 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002129}
2130
Brandon Jones6053a522014-07-25 16:22:09 -07002131void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002132{
Brandon Jones6053a522014-07-25 16:22:09 -07002133 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002134}
2135
Brandon Jones6053a522014-07-25 16:22:09 -07002136void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002137{
Brandon Jones6053a522014-07-25 16:22:09 -07002138 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002139}
2140
Brandon Jones6053a522014-07-25 16:22:09 -07002141
Jamie Madill4aa79e12014-09-29 10:46:14 -04002142void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002143{
2144 int baseWidth = getBaseLevelWidth();
2145 int baseHeight = getBaseLevelHeight();
2146 int baseDepth = getBaseLevelDepth();
2147 GLenum baseFormat = getBaseLevelInternalFormat();
2148
2149 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2150 int levelCount = mipLevels();
2151 for (int level = 1; level < levelCount; level++)
2152 {
2153 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2154 }
Brandon Jones142ec422014-07-16 10:31:30 -07002155}
2156
Jamie Madillac7579c2014-09-17 16:59:33 -04002157unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002158{
Jamie Madillc4833262014-09-18 16:18:26 -04002159 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002160}
2161
Jamie Madillac7579c2014-09-17 16:59:33 -04002162RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002163{
2164 // ensure the underlying texture is created
2165 if (!ensureRenderTarget())
2166 {
2167 return NULL;
2168 }
2169
Jamie Madillac7579c2014-09-17 16:59:33 -04002170 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002171 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002172}
2173
2174void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2175{
2176 // Only initialize the first time this texture is used as a render target or shader resource
2177 if (mTexStorage)
2178 {
2179 return;
2180 }
2181
2182 // do not attempt to create storage for nonexistant data
2183 if (!isLevelComplete(0))
2184 {
2185 return;
2186 }
2187
2188 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2189
2190 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2191 ASSERT(mTexStorage);
2192
2193 // flush image data to the storage
2194 updateStorage();
2195}
2196
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002197TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002198{
2199 GLsizei width = getBaseLevelWidth();
2200 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002201 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002202 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002203
2204 ASSERT(width > 0 && height > 0 && depth > 0);
2205
2206 // use existing storage level count, when previously specified by TexStorage*D
2207 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2208
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002209 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002210}
2211
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002212void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002213{
2214 SafeDelete(mTexStorage);
2215 mTexStorage = newCompleteTexStorage;
2216 mDirtyImages = true;
2217
2218 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2219 ASSERT(!mTexStorage->isManaged());
2220}
2221
2222void TextureD3D_2DArray::updateStorage()
2223{
2224 ASSERT(mTexStorage != NULL);
2225 GLint storageLevels = mTexStorage->getLevelCount();
2226 for (int level = 0; level < storageLevels; level++)
2227 {
2228 if (isLevelComplete(level))
2229 {
2230 updateStorageLevel(level);
2231 }
2232 }
2233}
2234
Brandon Jones142ec422014-07-16 10:31:30 -07002235bool TextureD3D_2DArray::isValidLevel(int level) const
2236{
2237 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2238}
2239
2240bool TextureD3D_2DArray::isLevelComplete(int level) const
2241{
2242 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2243
2244 if (isImmutable())
2245 {
2246 return true;
2247 }
2248
2249 GLsizei width = getBaseLevelWidth();
2250 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002251 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002252
2253 if (width <= 0 || height <= 0 || layers <= 0)
2254 {
2255 return false;
2256 }
2257
2258 if (level == 0)
2259 {
2260 return true;
2261 }
2262
2263 if (getInternalFormat(level) != getInternalFormat(0))
2264 {
2265 return false;
2266 }
2267
2268 if (getWidth(level) != std::max(1, width >> level))
2269 {
2270 return false;
2271 }
2272
2273 if (getHeight(level) != std::max(1, height >> level))
2274 {
2275 return false;
2276 }
2277
Jamie Madill3269bcb2014-09-30 16:33:52 -04002278 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002279 {
2280 return false;
2281 }
2282
2283 return true;
2284}
2285
2286void TextureD3D_2DArray::updateStorageLevel(int level)
2287{
2288 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2289 ASSERT(isLevelComplete(level));
2290
2291 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2292 {
2293 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2294 if (mImageArray[level][layer]->isDirty())
2295 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002296 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2297 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2298 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002299 }
2300 }
2301}
2302
2303void TextureD3D_2DArray::deleteImages()
2304{
2305 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2306 {
2307 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2308 {
2309 delete mImageArray[level][layer];
2310 }
2311 delete[] mImageArray[level];
2312 mImageArray[level] = NULL;
2313 mLayerCounts[level] = 0;
2314 }
2315}
2316
2317void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2318{
2319 // If there currently is a corresponding storage texture image, it has these parameters
2320 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2321 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002322 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002323 const GLenum storageFormat = getBaseLevelInternalFormat();
2324
2325 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2326 {
2327 delete mImageArray[level][layer];
2328 }
2329 delete[] mImageArray[level];
2330 mImageArray[level] = NULL;
2331 mLayerCounts[level] = depth;
2332
2333 if (depth > 0)
2334 {
2335 mImageArray[level] = new ImageD3D*[depth]();
2336
2337 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2338 {
2339 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2340 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2341 }
2342 }
2343
2344 if (mTexStorage)
2345 {
2346 const int storageLevels = mTexStorage->getLevelCount();
2347
2348 if ((level >= storageLevels && storageLevels != 0) ||
2349 width != storageWidth ||
2350 height != storageHeight ||
2351 depth != storageDepth ||
2352 internalformat != storageFormat) // Discard mismatched storage
2353 {
2354 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2355 {
2356 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2357 {
2358 mImageArray[level][layer]->markDirty();
2359 }
2360 }
2361
2362 delete mTexStorage;
2363 mTexStorage = NULL;
2364 mDirtyImages = true;
2365 }
2366 }
2367}
2368
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002369gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002370{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002371 ASSERT(index.hasLayer());
2372 GLint level = index.mipIndex;
2373 GLint layerTarget = index.layerIndex;
2374
Jamie Madill3269bcb2014-09-30 16:33:52 -04002375 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002376 {
2377 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill6b51c1a2014-10-06 16:31:21 -04002378 gl::Error error = image->copyToStorage2DArray(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002379 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002380 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002381 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002382 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002383
2384 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002385 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002386
2387 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002388}
2389
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002390gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2391{
2392 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2393}
2394
Jamie Madillcb83dc12014-09-29 10:46:12 -04002395gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2396{
2397 return gl::ImageIndex::Make2DArray(mip, layer);
2398}
2399
Brandon Jones78b1acd2014-07-15 15:33:07 -07002400}