blob: f61fc0de6bd7b3d2194dc34446b9da82ac5eebaf [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Brandon Jonesf47bebc2014-07-09 14:28:42 -070029bool IsRenderTargetUsage(GLenum usage)
30{
31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
32}
33
Brandon Jones78b1acd2014-07-15 15:33:07 -070034TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070035 : mRenderer(renderer),
36 mUsage(GL_NONE),
37 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040038 mImmutable(false),
39 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070040{
41}
42
43TextureD3D::~TextureD3D()
44{
45}
46
Brandon Jones6053a522014-07-25 16:22:09 -070047TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
48{
49 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
50 return static_cast<TextureD3D*>(texture);
51}
52
Jamie Madill2f06dbf2014-09-18 15:08:50 -040053TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070054{
55 // ensure the underlying texture is created
56 initializeStorage(false);
57
Jamie Madill98553e32014-09-30 16:33:50 -040058 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070059 {
60 updateStorage();
61 }
62
Jamie Madill98553e32014-09-30 16:33:50 -040063 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070064}
65
Brandon Jonesf47bebc2014-07-09 14:28:42 -070066GLint TextureD3D::getBaseLevelWidth() const
67{
Brandon Jones78b1acd2014-07-15 15:33:07 -070068 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 return (baseImage ? baseImage->getWidth() : 0);
70}
71
72GLint TextureD3D::getBaseLevelHeight() const
73{
Brandon Jones78b1acd2014-07-15 15:33:07 -070074 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075 return (baseImage ? baseImage->getHeight() : 0);
76}
77
78GLint TextureD3D::getBaseLevelDepth() const
79{
Brandon Jones78b1acd2014-07-15 15:33:07 -070080 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070081 return (baseImage ? baseImage->getDepth() : 0);
82}
83
84// Note: "base level image" is loosely defined to be any image from the base level,
85// where in the base of 2D array textures and cube maps there are several. Don't use
86// the base level image for anything except querying texture format and size.
87GLenum TextureD3D::getBaseLevelInternalFormat() const
88{
Brandon Jones78b1acd2014-07-15 15:33:07 -070089 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070090 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
91}
92
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040093gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
95 // No-op
96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
97 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040098 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -070099 }
100
101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
103 const void *pixelData = pixels;
104
105 if (unpack.pixelBuffer.id() != 0)
106 {
107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
111 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
112 const void *bufferData = pixelBuffer->getImplementation()->getData();
113 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
114 }
115
116 if (pixelData != NULL)
117 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400118 gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 if (error.isError())
120 {
121 return error;
122 }
123
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 mDirtyImages = true;
125 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400126
127 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700128}
129
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400130gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
131 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700132{
133 const void *pixelData = pixels;
134
135 // CPU readback & copy where direct GPU copy is not supported
136 if (unpack.pixelBuffer.id() != 0)
137 {
138 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200139 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700140 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
141 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
142 const void *bufferData = pixelBuffer->getImplementation()->getData();
143 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
144 }
145
146 if (pixelData != NULL)
147 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400148 Image *image = getImage(index);
149 ASSERT(image);
150
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400151 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
152 type, pixelData);
153 if (error.isError())
154 {
155 return error;
156 }
157
Jamie Madille6b6da02014-10-02 11:03:14 -0400158 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
159 error = commitRegion(index, region);
160 if (error.isError())
161 {
162 return error;
163 }
164
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 mDirtyImages = true;
166 }
167
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400168 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700169}
170
Geoff Langb5348332014-09-02 13:16:34 -0400171gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700172{
173 if (pixels != NULL)
174 {
Geoff Langb5348332014-09-02 13:16:34 -0400175 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
176 if (error.isError())
177 {
178 return error;
179 }
180
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181 mDirtyImages = true;
182 }
Geoff Langb5348332014-09-02 13:16:34 -0400183
184 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700185}
186
Geoff Langb5348332014-09-02 13:16:34 -0400187gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700188 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700189{
190 if (pixels != NULL)
191 {
Geoff Langb5348332014-09-02 13:16:34 -0400192 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
193 if (error.isError())
194 {
195 return error;
196 }
197
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198 mDirtyImages = true;
199 }
200
Geoff Langb5348332014-09-02 13:16:34 -0400201 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700202}
203
204bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
205{
206 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
207}
208
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400209gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
210 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400212 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700213 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
214 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400215 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700216 }
217
218 // In order to perform the fast copy through the shader, we must have the right format, and be able
219 // to create a render target.
220 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
221
Jacek Cabana5521de2014-10-01 17:23:46 +0200222 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700223
Geoff Langae5122c2014-08-27 14:08:43 -0400224 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
225 if (error.isError())
226 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400227 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400228 }
229
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400230 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
233GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
234{
235 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
236 {
237 // Maximum number of levels
238 return gl::log2(std::max(std::max(width, height), depth)) + 1;
239 }
240 else
241 {
242 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
243 return 1;
244 }
245}
246
247int TextureD3D::mipLevels() const
248{
249 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
250}
251
Jamie Madill98553e32014-09-30 16:33:50 -0400252TextureStorage *TextureD3D::getStorage()
253{
254 return mTexStorage;
255}
256
Jamie Madill3269bcb2014-09-30 16:33:52 -0400257Image *TextureD3D::getBaseLevelImage() const
258{
259 return getImage(getImageIndex(0, 0));
260}
261
Jamie Madill4aa79e12014-09-29 10:46:14 -0400262void TextureD3D::generateMipmaps()
263{
264 // Set up proper image sizes.
265 initMipmapsImages();
266
267 // We know that all layers have the same dimension, for the texture to be complete
268 GLint layerCount = static_cast<GLint>(getLayerCount(0));
269 GLint mipCount = mipLevels();
270
271 // The following will create and initialize the storage, or update it if it exists
272 TextureStorage *storage = getNativeTexture();
273
274 bool renderableStorage = (storage && storage->isRenderTarget());
275
276 for (GLint layer = 0; layer < layerCount; ++layer)
277 {
278 for (GLint mip = 1; mip < mipCount; ++mip)
279 {
280 ASSERT(getLayerCount(mip) == layerCount);
281
282 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
283 gl::ImageIndex destIndex = getImageIndex(mip, layer);
284
285 if (renderableStorage)
286 {
287 // GPU-side mipmapping
288 storage->generateMipmap(sourceIndex, destIndex);
289 }
290 else
291 {
292 // CPU-side mipmapping
293 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
294 }
295 }
296 }
297}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700298
Jamie Madill135570a2014-09-30 16:33:51 -0400299bool TextureD3D::isBaseImageZeroSize() const
300{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400301 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400302
303 if (!baseImage || baseImage->getWidth() <= 0)
304 {
305 return true;
306 }
307
308 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
309 {
310 return true;
311 }
312
313 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
314 {
315 return true;
316 }
317
318 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
319 {
320 return true;
321 }
322
323 return false;
324}
325
326bool TextureD3D::ensureRenderTarget()
327{
328 initializeStorage(true);
329
330 if (!isBaseImageZeroSize())
331 {
332 ASSERT(mTexStorage);
333 if (!mTexStorage->isRenderTarget())
334 {
335 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
336
337 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
338 {
339 delete newRenderTargetStorage;
340 return gl::error(GL_OUT_OF_MEMORY, false);
341 }
342
343 setCompleteTexStorage(newRenderTargetStorage);
344 }
345 }
346
347 return (mTexStorage && mTexStorage->isRenderTarget());
348}
349
Brandon Jones78b1acd2014-07-15 15:33:07 -0700350TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400351 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700352{
353 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
354 {
355 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
356 }
357}
358
359TextureD3D_2D::~TextureD3D_2D()
360{
Austin Kinross69822602014-08-12 15:51:37 -0700361 // Delete the Images before the TextureStorage.
362 // Images might be relying on the TextureStorage for some of their data.
363 // 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 -0700364 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
365 {
366 delete mImageArray[i];
367 }
Austin Kinross69822602014-08-12 15:51:37 -0700368
369 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370}
371
Brandon Jonescef06ff2014-08-05 13:27:48 -0700372Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700373{
374 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700375 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700376 return mImageArray[level];
377}
378
Jamie Madillfeda4d22014-09-17 13:03:29 -0400379Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
380{
381 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400382 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400383 ASSERT(index.type == GL_TEXTURE_2D);
384 return mImageArray[index.mipIndex];
385}
386
Brandon Jonescef06ff2014-08-05 13:27:48 -0700387GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700388{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700389 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
390 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700391}
392
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700393GLsizei TextureD3D_2D::getWidth(GLint level) const
394{
395 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
396 return mImageArray[level]->getWidth();
397 else
398 return 0;
399}
400
401GLsizei TextureD3D_2D::getHeight(GLint level) const
402{
403 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
404 return mImageArray[level]->getHeight();
405 else
406 return 0;
407}
408
409GLenum TextureD3D_2D::getInternalFormat(GLint level) const
410{
411 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
412 return mImageArray[level]->getInternalFormat();
413 else
414 return GL_NONE;
415}
416
417GLenum TextureD3D_2D::getActualFormat(GLint level) const
418{
419 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
420 return mImageArray[level]->getActualFormat();
421 else
422 return GL_NONE;
423}
424
425bool TextureD3D_2D::isDepth(GLint level) const
426{
Geoff Lang5d601382014-07-22 15:14:06 -0400427 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700428}
429
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400430gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
431 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
432 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700433{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700434 ASSERT(target == GL_TEXTURE_2D && depth == 1);
435
Geoff Lang5d601382014-07-22 15:14:06 -0400436 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
437
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700438 bool fastUnpacked = false;
439
Brandon Jonescef06ff2014-08-05 13:27:48 -0700440 redefineImage(level, sizedInternalFormat, width, height);
441
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442 // Attempt a fast gpu copy of the pixel data to the surface
443 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
444 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400445 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
446
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700447 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400448 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700449 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
450
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400451 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700452 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400453 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
454 if (error.isError())
455 {
456 return error;
457 }
458
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700459 // Ensure we don't overwrite our newly initialized data
460 mImageArray[level]->markClean();
461
462 fastUnpacked = true;
463 }
464 }
465
466 if (!fastUnpacked)
467 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400468 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
469 if (error.isError())
470 {
471 return error;
472 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700473 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400474
475 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700476}
477
Geoff Langb5348332014-09-02 13:16:34 -0400478gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
479 GLsizei width, GLsizei height, GLsizei depth,
480 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700482 ASSERT(target == GL_TEXTURE_2D && depth == 1);
483
484 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
485 redefineImage(level, format, width, height);
486
Geoff Langb5348332014-09-02 13:16:34 -0400487 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700488}
489
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400490gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
491 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
492 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700494 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
495
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700496 bool fastUnpacked = false;
497
Jamie Madillac7579c2014-09-17 16:59:33 -0400498 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400499 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700500 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
501 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400502 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400504 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400506 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
507 if (error.isError())
508 {
509 return error;
510 }
511
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700512 // Ensure we don't overwrite our newly initialized data
513 mImageArray[level]->markClean();
514
515 fastUnpacked = true;
516 }
517 }
518
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400519 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700520 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400521 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
522 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700523 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400524
525 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700526}
527
Geoff Langb5348332014-09-02 13:16:34 -0400528gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
529 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
530 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
533
Geoff Langb5348332014-09-02 13:16:34 -0400534 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
535 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536 {
Geoff Langb5348332014-09-02 13:16:34 -0400537 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538 }
Geoff Langb5348332014-09-02 13:16:34 -0400539
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400540 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
541 gl::Box region(xoffset, yoffset, 0, width, height, 1);
542 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543}
544
Brandon Jonescef06ff2014-08-05 13:27:48 -0700545void 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 -0700546{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700547 ASSERT(target == GL_TEXTURE_2D);
548
549 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
550 redefineImage(level, sizedInternalFormat, width, height);
551
Jamie Madill82bf0c52014-10-03 11:50:53 -0400552 gl::Rectangle sourceRect(x, y, width, height);
553
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700554 if (!mImageArray[level]->isRenderableFormat())
555 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400556 mImageArray[level]->copy(0, 0, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700557 mDirtyImages = true;
558 }
559 else
560 {
561 ensureRenderTarget();
562 mImageArray[level]->markClean();
563
564 if (width != 0 && height != 0 && isValidLevel(level))
565 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400566 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567 }
568 }
569}
570
571void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
572{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700573 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
574
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
576 // the current level we're copying to is defined (with appropriate format, width & height)
577 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
578
Jamie Madill82bf0c52014-10-03 11:50:53 -0400579 gl::Rectangle sourceRect(x, y, width, height);
580
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700581 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
582 {
Jamie Madill82bf0c52014-10-03 11:50:53 -0400583 mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700584 mDirtyImages = true;
585 }
586 else
587 {
588 ensureRenderTarget();
589
590 if (isValidLevel(level))
591 {
592 updateStorageLevel(level);
593
Jamie Madill856d9d42014-09-18 15:08:49 -0400594 mRenderer->copyImage2D(source, sourceRect,
595 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
596 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700597 }
598 }
599}
600
Brandon Jonescef06ff2014-08-05 13:27:48 -0700601void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700602{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700603 ASSERT(target == GL_TEXTURE_2D && depth == 1);
604
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700605 for (int level = 0; level < levels; level++)
606 {
607 GLsizei levelWidth = std::max(1, width >> level);
608 GLsizei levelHeight = std::max(1, height >> level);
609 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
610 }
611
612 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
613 {
614 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
615 }
616
617 mImmutable = true;
618
Jamie Madillc4833262014-09-18 16:18:26 -0400619 bool renderTarget = IsRenderTargetUsage(mUsage);
620 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400621 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622}
623
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700624void TextureD3D_2D::bindTexImage(egl::Surface *surface)
625{
626 GLenum internalformat = surface->getFormat();
627
628 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
629
630 if (mTexStorage)
631 {
632 SafeDelete(mTexStorage);
633 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400634
635 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636
637 mDirtyImages = true;
638}
639
640void TextureD3D_2D::releaseTexImage()
641{
642 if (mTexStorage)
643 {
644 SafeDelete(mTexStorage);
645 }
646
647 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
648 {
649 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
650 }
651}
652
Jamie Madill4aa79e12014-09-29 10:46:14 -0400653void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700654{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700655 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700657 for (int level = 1; level < levelCount; level++)
658 {
659 redefineImage(level, getBaseLevelInternalFormat(),
660 std::max(getBaseLevelWidth() >> level, 1),
661 std::max(getBaseLevelHeight() >> level, 1));
662 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663}
664
Jamie Madillac7579c2014-09-17 16:59:33 -0400665unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700666{
Jamie Madillac7579c2014-09-17 16:59:33 -0400667 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400668 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669}
670
Jamie Madillac7579c2014-09-17 16:59:33 -0400671RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672{
Jamie Madillac7579c2014-09-17 16:59:33 -0400673 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700674
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700675 // ensure the underlying texture is created
676 if (!ensureRenderTarget())
677 {
678 return NULL;
679 }
680
Jamie Madillac7579c2014-09-17 16:59:33 -0400681 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400682 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683}
684
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700685bool TextureD3D_2D::isValidLevel(int level) const
686{
687 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
688}
689
690bool TextureD3D_2D::isLevelComplete(int level) const
691{
692 if (isImmutable())
693 {
694 return true;
695 }
696
Brandon Jones78b1acd2014-07-15 15:33:07 -0700697 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700698
699 GLsizei width = baseImage->getWidth();
700 GLsizei height = baseImage->getHeight();
701
702 if (width <= 0 || height <= 0)
703 {
704 return false;
705 }
706
707 // The base image level is complete if the width and height are positive
708 if (level == 0)
709 {
710 return true;
711 }
712
713 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700714 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700715
716 if (image->getInternalFormat() != baseImage->getInternalFormat())
717 {
718 return false;
719 }
720
721 if (image->getWidth() != std::max(1, width >> level))
722 {
723 return false;
724 }
725
726 if (image->getHeight() != std::max(1, height >> level))
727 {
728 return false;
729 }
730
731 return true;
732}
733
734// Constructs a native texture resource from the texture images
735void TextureD3D_2D::initializeStorage(bool renderTarget)
736{
737 // Only initialize the first time this texture is used as a render target or shader resource
738 if (mTexStorage)
739 {
740 return;
741 }
742
743 // do not attempt to create storage for nonexistant data
744 if (!isLevelComplete(0))
745 {
746 return;
747 }
748
749 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
750
751 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
752 ASSERT(mTexStorage);
753
754 // flush image data to the storage
755 updateStorage();
756}
757
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400758TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700759{
760 GLsizei width = getBaseLevelWidth();
761 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400762 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700763
764 ASSERT(width > 0 && height > 0);
765
766 // use existing storage level count, when previously specified by TexStorage*D
767 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
768
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400769 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770}
771
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400772void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700773{
774 SafeDelete(mTexStorage);
775 mTexStorage = newCompleteTexStorage;
776
777 if (mTexStorage && mTexStorage->isManaged())
778 {
779 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
780 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400781 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700782 }
783 }
784
785 mDirtyImages = true;
786}
787
788void TextureD3D_2D::updateStorage()
789{
790 ASSERT(mTexStorage != NULL);
791 GLint storageLevels = mTexStorage->getLevelCount();
792 for (int level = 0; level < storageLevels; level++)
793 {
794 if (mImageArray[level]->isDirty() && isLevelComplete(level))
795 {
796 updateStorageLevel(level);
797 }
798 }
799}
800
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700801void TextureD3D_2D::updateStorageLevel(int level)
802{
803 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
804 ASSERT(isLevelComplete(level));
805
806 if (mImageArray[level]->isDirty())
807 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400808 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
809 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
810 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700811 }
812}
813
814void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
815{
816 // If there currently is a corresponding storage texture image, it has these parameters
817 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
818 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
819 const GLenum storageFormat = getBaseLevelInternalFormat();
820
821 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
822
823 if (mTexStorage)
824 {
825 const int storageLevels = mTexStorage->getLevelCount();
826
827 if ((level >= storageLevels && storageLevels != 0) ||
828 width != storageWidth ||
829 height != storageHeight ||
830 internalformat != storageFormat) // Discard mismatched storage
831 {
832 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
833 {
834 mImageArray[i]->markDirty();
835 }
836
837 SafeDelete(mTexStorage);
838 mDirtyImages = true;
839 }
840 }
841}
842
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400843gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700844{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400845 ASSERT(!index.hasLayer());
846 GLint level = index.mipIndex;
847
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700848 if (isValidLevel(level))
849 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700850 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400851 gl::Error error = image->copyToStorage2D(mTexStorage, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400852 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700853 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400854 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700855 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400856
857 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700858 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400859
860 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700861}
862
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400863gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
864{
865 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
866}
Brandon Jones0511e802014-07-14 16:27:26 -0700867
Jamie Madillcb83dc12014-09-29 10:46:12 -0400868gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
869{
870 // "layer" does not apply to 2D Textures.
871 return gl::ImageIndex::Make2D(mip);
872}
873
Brandon Jones78b1acd2014-07-15 15:33:07 -0700874TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400875 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700876{
877 for (int i = 0; i < 6; i++)
878 {
879 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
880 {
881 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
882 }
883 }
884}
885
886TextureD3D_Cube::~TextureD3D_Cube()
887{
Austin Kinross69822602014-08-12 15:51:37 -0700888 // Delete the Images before the TextureStorage.
889 // Images might be relying on the TextureStorage for some of their data.
890 // 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 -0700891 for (int i = 0; i < 6; i++)
892 {
893 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
894 {
895 SafeDelete(mImageArray[i][j]);
896 }
897 }
Austin Kinross69822602014-08-12 15:51:37 -0700898
899 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700900}
901
Brandon Jonescef06ff2014-08-05 13:27:48 -0700902Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700903{
904 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700905 ASSERT(layer < 6);
906 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700907}
908
Jamie Madillfeda4d22014-09-17 13:03:29 -0400909Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
910{
911 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
912 ASSERT(index.layerIndex < 6);
913 return mImageArray[index.layerIndex][index.mipIndex];
914}
915
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700917{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700918 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
919 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700920}
921
Brandon Jonescef06ff2014-08-05 13:27:48 -0700922GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700923{
924 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700925 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700926 else
927 return GL_NONE;
928}
929
Brandon Jonescef06ff2014-08-05 13:27:48 -0700930bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700931{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700932 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700933}
934
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400935gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
936 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
937 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700938{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700939 ASSERT(depth == 1);
940
941 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400942 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700943
944 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
945
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400946 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700947}
948
Geoff Langb5348332014-09-02 13:16:34 -0400949gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
950 GLsizei width, GLsizei height, GLsizei depth,
951 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700952{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700953 ASSERT(depth == 1);
954
Brandon Jones0511e802014-07-14 16:27:26 -0700955 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700956 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
957
Brandon Jones0511e802014-07-14 16:27:26 -0700958 redefineImage(faceIndex, level, format, width, height);
959
Geoff Langb5348332014-09-02 13:16:34 -0400960 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700961}
962
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400963gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
964 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
965 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700966{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700967 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400968 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -0400969 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -0700970}
971
Geoff Langb5348332014-09-02 13:16:34 -0400972gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
973 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
974 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700975{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700976 ASSERT(depth == 1 && zoffset == 0);
977
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400978 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700979
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400980 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 -0400981 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700982 {
Geoff Langb5348332014-09-02 13:16:34 -0400983 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700984 }
Geoff Langb5348332014-09-02 13:16:34 -0400985
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400986 gl::Box region(xoffset, yoffset, 0, width, height, 1);
987 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -0700988}
989
990void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
991{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700992 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400993 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
994
Brandon Jones0511e802014-07-14 16:27:26 -0700995 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
996
Jamie Madill82bf0c52014-10-03 11:50:53 -0400997 gl::Rectangle sourceRect(x, y, width, height);
998
Brandon Jones0511e802014-07-14 16:27:26 -0700999 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1000 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001001 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001002 mDirtyImages = true;
1003 }
1004 else
1005 {
1006 ensureRenderTarget();
1007 mImageArray[faceIndex][level]->markClean();
1008
1009 ASSERT(width == height);
1010
1011 if (width > 0 && isValidFaceLevel(faceIndex, level))
1012 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001013 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001014 }
1015 }
1016}
1017
1018void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1019{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001020 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001021
1022 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1023 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1024 // rely on the "getBaseLevel*" methods reliably otherwise.
1025 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1026
Jamie Madill82bf0c52014-10-03 11:50:53 -04001027 gl::Rectangle sourceRect(x, y, width, height);
1028
Brandon Jones0511e802014-07-14 16:27:26 -07001029 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1030 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001031 mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
Brandon Jones0511e802014-07-14 16:27:26 -07001032 mDirtyImages = true;
1033 }
1034 else
1035 {
1036 ensureRenderTarget();
1037
1038 if (isValidFaceLevel(faceIndex, level))
1039 {
1040 updateStorageFaceLevel(faceIndex, level);
1041
Jamie Madill856d9d42014-09-18 15:08:49 -04001042 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1043 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001044 }
1045 }
1046}
1047
Brandon Jonescef06ff2014-08-05 13:27:48 -07001048void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001049{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001050 ASSERT(width == height);
1051 ASSERT(depth == 1);
1052
Brandon Jones0511e802014-07-14 16:27:26 -07001053 for (int level = 0; level < levels; level++)
1054 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001055 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001056 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1057 {
1058 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1059 }
1060 }
1061
1062 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1063 {
1064 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1065 {
1066 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1067 }
1068 }
1069
1070 mImmutable = true;
1071
Jamie Madillc4833262014-09-18 16:18:26 -04001072 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001073 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1074 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001075}
1076
Brandon Jones0511e802014-07-14 16:27:26 -07001077// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1078bool TextureD3D_Cube::isCubeComplete() const
1079{
1080 int baseWidth = getBaseLevelWidth();
1081 int baseHeight = getBaseLevelHeight();
1082 GLenum baseFormat = getBaseLevelInternalFormat();
1083
1084 if (baseWidth <= 0 || baseWidth != baseHeight)
1085 {
1086 return false;
1087 }
1088
1089 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1090 {
1091 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1092
1093 if (faceBaseImage.getWidth() != baseWidth ||
1094 faceBaseImage.getHeight() != baseHeight ||
1095 faceBaseImage.getInternalFormat() != baseFormat )
1096 {
1097 return false;
1098 }
1099 }
1100
1101 return true;
1102}
1103
Brandon Jones6053a522014-07-25 16:22:09 -07001104void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1105{
1106 UNREACHABLE();
1107}
1108
1109void TextureD3D_Cube::releaseTexImage()
1110{
1111 UNREACHABLE();
1112}
1113
1114
Jamie Madill4aa79e12014-09-29 10:46:14 -04001115void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001116{
1117 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1118 int levelCount = mipLevels();
1119 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1120 {
1121 for (int level = 1; level < levelCount; level++)
1122 {
1123 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1124 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1125 }
1126 }
Brandon Jones0511e802014-07-14 16:27:26 -07001127}
1128
Jamie Madillac7579c2014-09-17 16:59:33 -04001129unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001130{
Jamie Madillc4833262014-09-18 16:18:26 -04001131 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001132}
1133
Jamie Madillac7579c2014-09-17 16:59:33 -04001134RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001135{
Jamie Madillac7579c2014-09-17 16:59:33 -04001136 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001137
1138 // ensure the underlying texture is created
1139 if (!ensureRenderTarget())
1140 {
1141 return NULL;
1142 }
1143
Jamie Madillac7579c2014-09-17 16:59:33 -04001144 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001145 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001146}
1147
Brandon Jones0511e802014-07-14 16:27:26 -07001148void TextureD3D_Cube::initializeStorage(bool renderTarget)
1149{
1150 // Only initialize the first time this texture is used as a render target or shader resource
1151 if (mTexStorage)
1152 {
1153 return;
1154 }
1155
1156 // do not attempt to create storage for nonexistant data
1157 if (!isFaceLevelComplete(0, 0))
1158 {
1159 return;
1160 }
1161
1162 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1163
1164 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1165 ASSERT(mTexStorage);
1166
1167 // flush image data to the storage
1168 updateStorage();
1169}
1170
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001171TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001172{
1173 GLsizei size = getBaseLevelWidth();
1174
1175 ASSERT(size > 0);
1176
1177 // use existing storage level count, when previously specified by TexStorage*D
1178 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1179
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001180 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001181}
1182
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001183void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
1185 SafeDelete(mTexStorage);
1186 mTexStorage = newCompleteTexStorage;
1187
1188 if (mTexStorage && mTexStorage->isManaged())
1189 {
1190 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1191 {
1192 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1193 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001194 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001195 }
1196 }
1197 }
1198
1199 mDirtyImages = true;
1200}
1201
1202void TextureD3D_Cube::updateStorage()
1203{
1204 ASSERT(mTexStorage != NULL);
1205 GLint storageLevels = mTexStorage->getLevelCount();
1206 for (int face = 0; face < 6; face++)
1207 {
1208 for (int level = 0; level < storageLevels; level++)
1209 {
1210 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1211 {
1212 updateStorageFaceLevel(face, level);
1213 }
1214 }
1215 }
1216}
1217
Brandon Jones0511e802014-07-14 16:27:26 -07001218bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1219{
1220 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1221}
1222
Brandon Jones0511e802014-07-14 16:27:26 -07001223bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1224{
1225 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1226
1227 if (isImmutable())
1228 {
1229 return true;
1230 }
1231
1232 int baseSize = getBaseLevelWidth();
1233
1234 if (baseSize <= 0)
1235 {
1236 return false;
1237 }
1238
1239 // "isCubeComplete" checks for base level completeness and we must call that
1240 // to determine if any face at level 0 is complete. We omit that check here
1241 // to avoid re-checking cube-completeness for every face at level 0.
1242 if (level == 0)
1243 {
1244 return true;
1245 }
1246
1247 // Check that non-zero levels are consistent with the base level.
1248 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1249
1250 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1251 {
1252 return false;
1253 }
1254
1255 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1256 {
1257 return false;
1258 }
1259
1260 return true;
1261}
1262
1263void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1264{
1265 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1266 ImageD3D *image = mImageArray[faceIndex][level];
1267
1268 if (image->isDirty())
1269 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001270 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1271 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1272 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1273 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001274 }
1275}
1276
1277void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1278{
1279 // If there currently is a corresponding storage texture image, it has these parameters
1280 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1281 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1282 const GLenum storageFormat = getBaseLevelInternalFormat();
1283
1284 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1285
1286 if (mTexStorage)
1287 {
1288 const int storageLevels = mTexStorage->getLevelCount();
1289
1290 if ((level >= storageLevels && storageLevels != 0) ||
1291 width != storageWidth ||
1292 height != storageHeight ||
1293 internalformat != storageFormat) // Discard mismatched storage
1294 {
1295 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1296 {
1297 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1298 {
1299 mImageArray[faceIndex][level]->markDirty();
1300 }
1301 }
1302
1303 SafeDelete(mTexStorage);
1304
1305 mDirtyImages = true;
1306 }
1307 }
1308}
1309
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001310gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001311{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001312 ASSERT(index.hasLayer());
1313
1314 GLint level = index.mipIndex;
1315 int faceIndex = static_cast<int>(index.layerIndex);
1316
Brandon Jones0511e802014-07-14 16:27:26 -07001317 if (isValidFaceLevel(faceIndex, level))
1318 {
1319 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001320 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001321 if (error.isError())
1322 {
1323 return error;
1324 }
1325
1326 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001327 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001328
1329 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001330}
1331
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001332gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1333{
1334 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1335}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001336
Jamie Madillcb83dc12014-09-29 10:46:12 -04001337gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1338{
1339 // The "layer" of the image index corresponds to the cube face
1340 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1341}
1342
Brandon Jones78b1acd2014-07-15 15:33:07 -07001343TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001344 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001345{
1346 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1347 {
1348 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1349 }
1350}
1351
1352TextureD3D_3D::~TextureD3D_3D()
1353{
Austin Kinross69822602014-08-12 15:51:37 -07001354 // Delete the Images before the TextureStorage.
1355 // Images might be relying on the TextureStorage for some of their data.
1356 // 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 -07001357 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1358 {
1359 delete mImageArray[i];
1360 }
Austin Kinross69822602014-08-12 15:51:37 -07001361
1362 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001363}
1364
Brandon Jonescef06ff2014-08-05 13:27:48 -07001365Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001366{
1367 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001368 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001369 return mImageArray[level];
1370}
1371
Jamie Madillfeda4d22014-09-17 13:03:29 -04001372Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1373{
1374 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001375 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001376 ASSERT(index.type == GL_TEXTURE_3D);
1377 return mImageArray[index.mipIndex];
1378}
1379
Brandon Jonescef06ff2014-08-05 13:27:48 -07001380GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001381{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001382 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1383 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001384}
1385
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386GLsizei TextureD3D_3D::getWidth(GLint level) const
1387{
1388 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1389 return mImageArray[level]->getWidth();
1390 else
1391 return 0;
1392}
1393
1394GLsizei TextureD3D_3D::getHeight(GLint level) const
1395{
1396 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1397 return mImageArray[level]->getHeight();
1398 else
1399 return 0;
1400}
1401
1402GLsizei TextureD3D_3D::getDepth(GLint level) const
1403{
1404 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1405 return mImageArray[level]->getDepth();
1406 else
1407 return 0;
1408}
1409
1410GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1411{
1412 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1413 return mImageArray[level]->getInternalFormat();
1414 else
1415 return GL_NONE;
1416}
1417
1418bool TextureD3D_3D::isDepth(GLint level) const
1419{
Geoff Lang5d601382014-07-22 15:14:06 -04001420 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001421}
1422
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001423gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1424 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1425 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001426{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001427 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001428 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1429
Brandon Jones78b1acd2014-07-15 15:33:07 -07001430 redefineImage(level, sizedInternalFormat, width, height, depth);
1431
1432 bool fastUnpacked = false;
1433
1434 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1435 if (isFastUnpackable(unpack, sizedInternalFormat))
1436 {
1437 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001438 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1439 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001440 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1441
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001442 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001443 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001444 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1445 if (error.isError())
1446 {
1447 return error;
1448 }
1449
Brandon Jones78b1acd2014-07-15 15:33:07 -07001450 // Ensure we don't overwrite our newly initialized data
1451 mImageArray[level]->markClean();
1452
1453 fastUnpacked = true;
1454 }
1455 }
1456
1457 if (!fastUnpacked)
1458 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001459 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1460 if (error.isError())
1461 {
1462 return error;
1463 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001464 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001465
1466 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001467}
1468
Geoff Langb5348332014-09-02 13:16:34 -04001469gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1470 GLsizei width, GLsizei height,GLsizei depth,
1471 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001472{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001473 ASSERT(target == GL_TEXTURE_3D);
1474
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1476 redefineImage(level, format, width, height, depth);
1477
Geoff Langb5348332014-09-02 13:16:34 -04001478 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479}
1480
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001481gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1482 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1483 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001484{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001485 ASSERT(target == GL_TEXTURE_3D);
1486
Brandon Jones78b1acd2014-07-15 15:33:07 -07001487 bool fastUnpacked = false;
1488
Jamie Madillac7579c2014-09-17 16:59:33 -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, getInternalFormat(level)))
1493 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001494 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001496 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001497 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001498 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001499 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1500 if (error.isError())
1501 {
1502 return error;
1503 }
1504
Brandon Jones78b1acd2014-07-15 15:33:07 -07001505 // Ensure we don't overwrite our newly initialized data
1506 mImageArray[level]->markClean();
1507
1508 fastUnpacked = true;
1509 }
1510 }
1511
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001512 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001513 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001514 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1515 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001517
1518 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001519}
1520
Geoff Langb5348332014-09-02 13:16:34 -04001521gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1522 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1523 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001524{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001525 ASSERT(target == GL_TEXTURE_3D);
1526
Geoff Langb5348332014-09-02 13:16:34 -04001527 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1528 format, imageSize, pixels, mImageArray[level]);
1529 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001530 {
Geoff Langb5348332014-09-02 13:16:34 -04001531 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001532 }
Geoff Langb5348332014-09-02 13:16:34 -04001533
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001534 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1535 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1536 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001537}
1538
Brandon Jonescef06ff2014-08-05 13:27:48 -07001539void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1540{
1541 UNIMPLEMENTED();
1542}
1543
Brandon Jones78b1acd2014-07-15 15:33:07 -07001544void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1545{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001546 ASSERT(target == GL_TEXTURE_3D);
1547
Brandon Jones78b1acd2014-07-15 15:33:07 -07001548 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1549 // the current level we're copying to is defined (with appropriate format, width & height)
1550 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1551
Jamie Madill82bf0c52014-10-03 11:50:53 -04001552 gl::Rectangle sourceRect(x, y, width, height);
1553
Brandon Jones78b1acd2014-07-15 15:33:07 -07001554 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1555 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04001556 mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001557 mDirtyImages = true;
1558 }
1559 else
1560 {
1561 ensureRenderTarget();
1562
1563 if (isValidLevel(level))
1564 {
1565 updateStorageLevel(level);
1566
Jamie Madill856d9d42014-09-18 15:08:49 -04001567 mRenderer->copyImage3D(source, sourceRect,
1568 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1569 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001570 }
1571 }
1572}
1573
Brandon Jonescef06ff2014-08-05 13:27:48 -07001574void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001575{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001576 ASSERT(target == GL_TEXTURE_3D);
1577
Brandon Jones78b1acd2014-07-15 15:33:07 -07001578 for (int level = 0; level < levels; level++)
1579 {
1580 GLsizei levelWidth = std::max(1, width >> level);
1581 GLsizei levelHeight = std::max(1, height >> level);
1582 GLsizei levelDepth = std::max(1, depth >> level);
1583 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1584 }
1585
1586 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1587 {
1588 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1589 }
1590
1591 mImmutable = true;
1592
Jamie Madillc4833262014-09-18 16:18:26 -04001593 bool renderTarget = IsRenderTargetUsage(mUsage);
1594 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001595 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001596}
1597
Brandon Jones6053a522014-07-25 16:22:09 -07001598void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001599{
Brandon Jones6053a522014-07-25 16:22:09 -07001600 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001601}
1602
Brandon Jones6053a522014-07-25 16:22:09 -07001603void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001604{
Brandon Jones6053a522014-07-25 16:22:09 -07001605 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001606}
1607
Brandon Jones6053a522014-07-25 16:22:09 -07001608
Jamie Madill4aa79e12014-09-29 10:46:14 -04001609void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001610{
1611 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1612 int levelCount = mipLevels();
1613 for (int level = 1; level < levelCount; level++)
1614 {
1615 redefineImage(level, getBaseLevelInternalFormat(),
1616 std::max(getBaseLevelWidth() >> level, 1),
1617 std::max(getBaseLevelHeight() >> level, 1),
1618 std::max(getBaseLevelDepth() >> level, 1));
1619 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001620}
1621
Jamie Madillac7579c2014-09-17 16:59:33 -04001622unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001623{
Jamie Madillc4833262014-09-18 16:18:26 -04001624 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001625}
1626
Jamie Madillac7579c2014-09-17 16:59:33 -04001627RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001628{
1629 // ensure the underlying texture is created
1630 if (!ensureRenderTarget())
1631 {
1632 return NULL;
1633 }
1634
Jamie Madillac7579c2014-09-17 16:59:33 -04001635 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001636 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001637 updateStorage();
1638 }
1639 else
1640 {
1641 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001642 }
1643
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001644 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001645}
1646
1647void TextureD3D_3D::initializeStorage(bool renderTarget)
1648{
1649 // Only initialize the first time this texture is used as a render target or shader resource
1650 if (mTexStorage)
1651 {
1652 return;
1653 }
1654
1655 // do not attempt to create storage for nonexistant data
1656 if (!isLevelComplete(0))
1657 {
1658 return;
1659 }
1660
1661 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1662
1663 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1664 ASSERT(mTexStorage);
1665
1666 // flush image data to the storage
1667 updateStorage();
1668}
1669
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001670TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001671{
1672 GLsizei width = getBaseLevelWidth();
1673 GLsizei height = getBaseLevelHeight();
1674 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001675 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001676
1677 ASSERT(width > 0 && height > 0 && depth > 0);
1678
1679 // use existing storage level count, when previously specified by TexStorage*D
1680 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1681
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001682 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683}
1684
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001685void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001686{
1687 SafeDelete(mTexStorage);
1688 mTexStorage = newCompleteTexStorage;
1689 mDirtyImages = true;
1690
1691 // We do not support managed 3D storage, as that is D3D9/ES2-only
1692 ASSERT(!mTexStorage->isManaged());
1693}
1694
1695void TextureD3D_3D::updateStorage()
1696{
1697 ASSERT(mTexStorage != NULL);
1698 GLint storageLevels = mTexStorage->getLevelCount();
1699 for (int level = 0; level < storageLevels; level++)
1700 {
1701 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1702 {
1703 updateStorageLevel(level);
1704 }
1705 }
1706}
1707
Brandon Jones78b1acd2014-07-15 15:33:07 -07001708bool TextureD3D_3D::isValidLevel(int level) const
1709{
1710 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1711}
1712
1713bool TextureD3D_3D::isLevelComplete(int level) const
1714{
1715 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1716
1717 if (isImmutable())
1718 {
1719 return true;
1720 }
1721
1722 GLsizei width = getBaseLevelWidth();
1723 GLsizei height = getBaseLevelHeight();
1724 GLsizei depth = getBaseLevelDepth();
1725
1726 if (width <= 0 || height <= 0 || depth <= 0)
1727 {
1728 return false;
1729 }
1730
1731 if (level == 0)
1732 {
1733 return true;
1734 }
1735
1736 ImageD3D *levelImage = mImageArray[level];
1737
1738 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1739 {
1740 return false;
1741 }
1742
1743 if (levelImage->getWidth() != std::max(1, width >> level))
1744 {
1745 return false;
1746 }
1747
1748 if (levelImage->getHeight() != std::max(1, height >> level))
1749 {
1750 return false;
1751 }
1752
1753 if (levelImage->getDepth() != std::max(1, depth >> level))
1754 {
1755 return false;
1756 }
1757
1758 return true;
1759}
1760
1761void TextureD3D_3D::updateStorageLevel(int level)
1762{
1763 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1764 ASSERT(isLevelComplete(level));
1765
1766 if (mImageArray[level]->isDirty())
1767 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001768 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1769 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1770 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001771 }
1772}
1773
1774void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1775{
1776 // If there currently is a corresponding storage texture image, it has these parameters
1777 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1778 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1779 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1780 const GLenum storageFormat = getBaseLevelInternalFormat();
1781
1782 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1783
1784 if (mTexStorage)
1785 {
1786 const int storageLevels = mTexStorage->getLevelCount();
1787
1788 if ((level >= storageLevels && storageLevels != 0) ||
1789 width != storageWidth ||
1790 height != storageHeight ||
1791 depth != storageDepth ||
1792 internalformat != storageFormat) // Discard mismatched storage
1793 {
1794 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1795 {
1796 mImageArray[i]->markDirty();
1797 }
1798
1799 SafeDelete(mTexStorage);
1800 mDirtyImages = true;
1801 }
1802 }
1803}
1804
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001805gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001807 ASSERT(!index.hasLayer());
1808 GLint level = index.mipIndex;
1809
Brandon Jones78b1acd2014-07-15 15:33:07 -07001810 if (isValidLevel(level))
1811 {
1812 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001813 gl::Error error = image->copyToStorage3D(mTexStorage, level, region.x, region.y, region.z, region.width, region.height, region.depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001814 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001816 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001817 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001818
1819 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001820 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001821
1822 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001823}
1824
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001825gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1826{
1827 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1828 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1829}
Brandon Jones142ec422014-07-16 10:31:30 -07001830
Jamie Madillcb83dc12014-09-29 10:46:12 -04001831gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1832{
1833 // The "layer" here does not apply to 3D images. We use one Image per mip.
1834 return gl::ImageIndex::Make3D(mip);
1835}
1836
Brandon Jones142ec422014-07-16 10:31:30 -07001837TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001838 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001839{
1840 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1841 {
1842 mLayerCounts[level] = 0;
1843 mImageArray[level] = NULL;
1844 }
1845}
1846
1847TextureD3D_2DArray::~TextureD3D_2DArray()
1848{
Austin Kinross69822602014-08-12 15:51:37 -07001849 // Delete the Images before the TextureStorage.
1850 // Images might be relying on the TextureStorage for some of their data.
1851 // 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 -07001852 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001853 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001854}
1855
Brandon Jones142ec422014-07-16 10:31:30 -07001856Image *TextureD3D_2DArray::getImage(int level, int layer) const
1857{
1858 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1859 ASSERT(layer < mLayerCounts[level]);
1860 return mImageArray[level][layer];
1861}
1862
Jamie Madillfeda4d22014-09-17 13:03:29 -04001863Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1864{
1865 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1866 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1867 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1868 return mImageArray[index.mipIndex][index.layerIndex];
1869}
1870
Brandon Jones142ec422014-07-16 10:31:30 -07001871GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1872{
1873 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1874 return mLayerCounts[level];
1875}
1876
Brandon Jones142ec422014-07-16 10:31:30 -07001877GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1878{
1879 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1880}
1881
1882GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1883{
1884 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1885}
1886
Brandon Jones142ec422014-07-16 10:31:30 -07001887GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1888{
1889 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1890}
1891
1892bool TextureD3D_2DArray::isDepth(GLint level) const
1893{
Geoff Lang5d601382014-07-22 15:14:06 -04001894 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001895}
1896
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001897gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1898 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1899 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001900{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001901 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1902
Geoff Lang5d601382014-07-22 15:14:06 -04001903 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1904
Brandon Jones142ec422014-07-16 10:31:30 -07001905 redefineImage(level, sizedInternalFormat, width, height, depth);
1906
Geoff Lang5d601382014-07-22 15:14:06 -04001907 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1908 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001909
1910 for (int i = 0; i < depth; i++)
1911 {
1912 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001913 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1914 if (error.isError())
1915 {
1916 return error;
1917 }
Brandon Jones142ec422014-07-16 10:31:30 -07001918 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001919
1920 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001921}
1922
Geoff Langb5348332014-09-02 13:16:34 -04001923gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1924 GLsizei width, GLsizei height, GLsizei depth,
1925 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001926{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001927 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1928
Brandon Jones142ec422014-07-16 10:31:30 -07001929 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1930 redefineImage(level, format, width, height, depth);
1931
Geoff Lang5d601382014-07-22 15:14:06 -04001932 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1933 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001934
1935 for (int i = 0; i < depth; i++)
1936 {
1937 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001938 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1939 if (error.isError())
1940 {
1941 return error;
1942 }
Brandon Jones142ec422014-07-16 10:31:30 -07001943 }
Geoff Langb5348332014-09-02 13:16:34 -04001944
1945 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001946}
1947
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001948gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1949 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1950 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001951{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001952 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1953
Geoff Lang5d601382014-07-22 15:14:06 -04001954 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1955 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001956
1957 for (int i = 0; i < depth; i++)
1958 {
1959 int layer = zoffset + i;
1960 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1961
Jamie Madillfeda4d22014-09-17 13:03:29 -04001962 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04001963 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
1964 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001965 if (error.isError())
1966 {
1967 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07001968 }
1969 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001970
1971 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001972}
1973
Geoff Langb5348332014-09-02 13:16:34 -04001974gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1975 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1976 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001977{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001978 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1979
Geoff Lang5d601382014-07-22 15:14:06 -04001980 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1981 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001982
1983 for (int i = 0; i < depth; i++)
1984 {
1985 int layer = zoffset + i;
1986 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1987
Geoff Langb5348332014-09-02 13:16:34 -04001988 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
1989 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07001990 {
Geoff Langb5348332014-09-02 13:16:34 -04001991 return error;
1992 }
1993
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001994 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
1995 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1996 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04001997 if (error.isError())
1998 {
1999 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002000 }
2001 }
Geoff Langb5348332014-09-02 13:16:34 -04002002
2003 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002004}
2005
Brandon Jonescef06ff2014-08-05 13:27:48 -07002006void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2007{
2008 UNIMPLEMENTED();
2009}
2010
Brandon Jones142ec422014-07-16 10:31:30 -07002011void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2012{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002013 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2014
Brandon Jones142ec422014-07-16 10:31:30 -07002015 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2016 // the current level we're copying to is defined (with appropriate format, width & height)
2017 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2018
Jamie Madill82bf0c52014-10-03 11:50:53 -04002019 gl::Rectangle sourceRect(x, y, width, height);
2020
Brandon Jones142ec422014-07-16 10:31:30 -07002021 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2022 {
Jamie Madill82bf0c52014-10-03 11:50:53 -04002023 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
Brandon Jones142ec422014-07-16 10:31:30 -07002024 mDirtyImages = true;
2025 }
2026 else
2027 {
2028 ensureRenderTarget();
2029
2030 if (isValidLevel(level))
2031 {
2032 updateStorageLevel(level);
2033
Jamie Madill856d9d42014-09-18 15:08:49 -04002034 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2035 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002036 }
2037 }
2038}
2039
Brandon Jonescef06ff2014-08-05 13:27:48 -07002040void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002041{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002042 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2043
Brandon Jones142ec422014-07-16 10:31:30 -07002044 deleteImages();
2045
2046 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2047 {
2048 GLsizei levelWidth = std::max(1, width >> level);
2049 GLsizei levelHeight = std::max(1, height >> level);
2050
2051 mLayerCounts[level] = (level < levels ? depth : 0);
2052
2053 if (mLayerCounts[level] > 0)
2054 {
2055 // Create new images for this level
2056 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2057
2058 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2059 {
2060 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2061 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2062 levelHeight, 1, true);
2063 }
2064 }
2065 }
2066
2067 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002068
2069 bool renderTarget = IsRenderTargetUsage(mUsage);
2070 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002071 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002072}
2073
Brandon Jones6053a522014-07-25 16:22:09 -07002074void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002075{
Brandon Jones6053a522014-07-25 16:22:09 -07002076 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002077}
2078
Brandon Jones6053a522014-07-25 16:22:09 -07002079void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002080{
Brandon Jones6053a522014-07-25 16:22:09 -07002081 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002082}
2083
Brandon Jones6053a522014-07-25 16:22:09 -07002084
Jamie Madill4aa79e12014-09-29 10:46:14 -04002085void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002086{
2087 int baseWidth = getBaseLevelWidth();
2088 int baseHeight = getBaseLevelHeight();
2089 int baseDepth = getBaseLevelDepth();
2090 GLenum baseFormat = getBaseLevelInternalFormat();
2091
2092 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2093 int levelCount = mipLevels();
2094 for (int level = 1; level < levelCount; level++)
2095 {
2096 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2097 }
Brandon Jones142ec422014-07-16 10:31:30 -07002098}
2099
Jamie Madillac7579c2014-09-17 16:59:33 -04002100unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002101{
Jamie Madillc4833262014-09-18 16:18:26 -04002102 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002103}
2104
Jamie Madillac7579c2014-09-17 16:59:33 -04002105RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002106{
2107 // ensure the underlying texture is created
2108 if (!ensureRenderTarget())
2109 {
2110 return NULL;
2111 }
2112
Jamie Madillac7579c2014-09-17 16:59:33 -04002113 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002114 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002115}
2116
2117void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2118{
2119 // Only initialize the first time this texture is used as a render target or shader resource
2120 if (mTexStorage)
2121 {
2122 return;
2123 }
2124
2125 // do not attempt to create storage for nonexistant data
2126 if (!isLevelComplete(0))
2127 {
2128 return;
2129 }
2130
2131 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2132
2133 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2134 ASSERT(mTexStorage);
2135
2136 // flush image data to the storage
2137 updateStorage();
2138}
2139
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002140TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002141{
2142 GLsizei width = getBaseLevelWidth();
2143 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002144 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002145 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002146
2147 ASSERT(width > 0 && height > 0 && depth > 0);
2148
2149 // use existing storage level count, when previously specified by TexStorage*D
2150 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2151
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002152 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002153}
2154
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002155void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002156{
2157 SafeDelete(mTexStorage);
2158 mTexStorage = newCompleteTexStorage;
2159 mDirtyImages = true;
2160
2161 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2162 ASSERT(!mTexStorage->isManaged());
2163}
2164
2165void TextureD3D_2DArray::updateStorage()
2166{
2167 ASSERT(mTexStorage != NULL);
2168 GLint storageLevels = mTexStorage->getLevelCount();
2169 for (int level = 0; level < storageLevels; level++)
2170 {
2171 if (isLevelComplete(level))
2172 {
2173 updateStorageLevel(level);
2174 }
2175 }
2176}
2177
Brandon Jones142ec422014-07-16 10:31:30 -07002178bool TextureD3D_2DArray::isValidLevel(int level) const
2179{
2180 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2181}
2182
2183bool TextureD3D_2DArray::isLevelComplete(int level) const
2184{
2185 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2186
2187 if (isImmutable())
2188 {
2189 return true;
2190 }
2191
2192 GLsizei width = getBaseLevelWidth();
2193 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002194 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002195
2196 if (width <= 0 || height <= 0 || layers <= 0)
2197 {
2198 return false;
2199 }
2200
2201 if (level == 0)
2202 {
2203 return true;
2204 }
2205
2206 if (getInternalFormat(level) != getInternalFormat(0))
2207 {
2208 return false;
2209 }
2210
2211 if (getWidth(level) != std::max(1, width >> level))
2212 {
2213 return false;
2214 }
2215
2216 if (getHeight(level) != std::max(1, height >> level))
2217 {
2218 return false;
2219 }
2220
Jamie Madill3269bcb2014-09-30 16:33:52 -04002221 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002222 {
2223 return false;
2224 }
2225
2226 return true;
2227}
2228
2229void TextureD3D_2DArray::updateStorageLevel(int level)
2230{
2231 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2232 ASSERT(isLevelComplete(level));
2233
2234 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2235 {
2236 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2237 if (mImageArray[level][layer]->isDirty())
2238 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002239 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2240 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2241 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002242 }
2243 }
2244}
2245
2246void TextureD3D_2DArray::deleteImages()
2247{
2248 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2249 {
2250 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2251 {
2252 delete mImageArray[level][layer];
2253 }
2254 delete[] mImageArray[level];
2255 mImageArray[level] = NULL;
2256 mLayerCounts[level] = 0;
2257 }
2258}
2259
2260void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2261{
2262 // If there currently is a corresponding storage texture image, it has these parameters
2263 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2264 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002265 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002266 const GLenum storageFormat = getBaseLevelInternalFormat();
2267
2268 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2269 {
2270 delete mImageArray[level][layer];
2271 }
2272 delete[] mImageArray[level];
2273 mImageArray[level] = NULL;
2274 mLayerCounts[level] = depth;
2275
2276 if (depth > 0)
2277 {
2278 mImageArray[level] = new ImageD3D*[depth]();
2279
2280 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2281 {
2282 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2283 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2284 }
2285 }
2286
2287 if (mTexStorage)
2288 {
2289 const int storageLevels = mTexStorage->getLevelCount();
2290
2291 if ((level >= storageLevels && storageLevels != 0) ||
2292 width != storageWidth ||
2293 height != storageHeight ||
2294 depth != storageDepth ||
2295 internalformat != storageFormat) // Discard mismatched storage
2296 {
2297 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2298 {
2299 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2300 {
2301 mImageArray[level][layer]->markDirty();
2302 }
2303 }
2304
2305 delete mTexStorage;
2306 mTexStorage = NULL;
2307 mDirtyImages = true;
2308 }
2309 }
2310}
2311
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002312gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002313{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002314 ASSERT(index.hasLayer());
2315 GLint level = index.mipIndex;
2316 GLint layerTarget = index.layerIndex;
2317
Jamie Madill3269bcb2014-09-30 16:33:52 -04002318 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002319 {
2320 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002321 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, region.x, region.y, layerTarget, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002322 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002323 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002324 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002325 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002326
2327 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002328 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002329
2330 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002331}
2332
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002333gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2334{
2335 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2336}
2337
Jamie Madillcb83dc12014-09-29 10:46:12 -04002338gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2339{
2340 return gl::ImageIndex::Make2DArray(mip, layer);
2341}
2342
Brandon Jones78b1acd2014-07-15 15:33:07 -07002343}