blob: d0621331dbd3bd119dc04bfb72d644392a5368ce [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
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158 mDirtyImages = true;
159 }
160
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400161 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162}
163
Geoff Langb5348332014-09-02 13:16:34 -0400164gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165{
166 if (pixels != NULL)
167 {
Geoff Langb5348332014-09-02 13:16:34 -0400168 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
169 if (error.isError())
170 {
171 return error;
172 }
173
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174 mDirtyImages = true;
175 }
Geoff Langb5348332014-09-02 13:16:34 -0400176
177 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700178}
179
Geoff Langb5348332014-09-02 13:16:34 -0400180gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700181 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700182{
183 if (pixels != NULL)
184 {
Geoff Langb5348332014-09-02 13:16:34 -0400185 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
186 if (error.isError())
187 {
188 return error;
189 }
190
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191 mDirtyImages = true;
192 }
193
Geoff Langb5348332014-09-02 13:16:34 -0400194 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195}
196
197bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
198{
199 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
200}
201
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400202gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
203 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700204{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400205 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700206 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
207 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400208 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700209 }
210
211 // In order to perform the fast copy through the shader, we must have the right format, and be able
212 // to create a render target.
213 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
214
Jacek Cabana5521de2014-10-01 17:23:46 +0200215 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700216
Geoff Langae5122c2014-08-27 14:08:43 -0400217 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
218 if (error.isError())
219 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400220 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400221 }
222
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400223 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700224}
225
226GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
227{
228 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
229 {
230 // Maximum number of levels
231 return gl::log2(std::max(std::max(width, height), depth)) + 1;
232 }
233 else
234 {
235 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
236 return 1;
237 }
238}
239
240int TextureD3D::mipLevels() const
241{
242 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
243}
244
Jamie Madill98553e32014-09-30 16:33:50 -0400245TextureStorage *TextureD3D::getStorage()
246{
247 return mTexStorage;
248}
249
Jamie Madill3269bcb2014-09-30 16:33:52 -0400250Image *TextureD3D::getBaseLevelImage() const
251{
252 return getImage(getImageIndex(0, 0));
253}
254
Jamie Madill4aa79e12014-09-29 10:46:14 -0400255void TextureD3D::generateMipmaps()
256{
257 // Set up proper image sizes.
258 initMipmapsImages();
259
260 // We know that all layers have the same dimension, for the texture to be complete
261 GLint layerCount = static_cast<GLint>(getLayerCount(0));
262 GLint mipCount = mipLevels();
263
264 // The following will create and initialize the storage, or update it if it exists
265 TextureStorage *storage = getNativeTexture();
266
267 bool renderableStorage = (storage && storage->isRenderTarget());
268
269 for (GLint layer = 0; layer < layerCount; ++layer)
270 {
271 for (GLint mip = 1; mip < mipCount; ++mip)
272 {
273 ASSERT(getLayerCount(mip) == layerCount);
274
275 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
276 gl::ImageIndex destIndex = getImageIndex(mip, layer);
277
278 if (renderableStorage)
279 {
280 // GPU-side mipmapping
281 storage->generateMipmap(sourceIndex, destIndex);
282 }
283 else
284 {
285 // CPU-side mipmapping
286 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
287 }
288 }
289 }
290}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700291
Jamie Madill135570a2014-09-30 16:33:51 -0400292bool TextureD3D::isBaseImageZeroSize() const
293{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400294 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400295
296 if (!baseImage || baseImage->getWidth() <= 0)
297 {
298 return true;
299 }
300
301 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
302 {
303 return true;
304 }
305
306 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
307 {
308 return true;
309 }
310
311 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
312 {
313 return true;
314 }
315
316 return false;
317}
318
319bool TextureD3D::ensureRenderTarget()
320{
321 initializeStorage(true);
322
323 if (!isBaseImageZeroSize())
324 {
325 ASSERT(mTexStorage);
326 if (!mTexStorage->isRenderTarget())
327 {
328 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
329
330 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
331 {
332 delete newRenderTargetStorage;
333 return gl::error(GL_OUT_OF_MEMORY, false);
334 }
335
336 setCompleteTexStorage(newRenderTargetStorage);
337 }
338 }
339
340 return (mTexStorage && mTexStorage->isRenderTarget());
341}
342
Brandon Jones78b1acd2014-07-15 15:33:07 -0700343TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400344 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700345{
346 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
347 {
348 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
349 }
350}
351
352TextureD3D_2D::~TextureD3D_2D()
353{
Austin Kinross69822602014-08-12 15:51:37 -0700354 // Delete the Images before the TextureStorage.
355 // Images might be relying on the TextureStorage for some of their data.
356 // 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 -0700357 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
358 {
359 delete mImageArray[i];
360 }
Austin Kinross69822602014-08-12 15:51:37 -0700361
362 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700363}
364
Brandon Jonescef06ff2014-08-05 13:27:48 -0700365Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700366{
367 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700368 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700369 return mImageArray[level];
370}
371
Jamie Madillfeda4d22014-09-17 13:03:29 -0400372Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
373{
374 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400375 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400376 ASSERT(index.type == GL_TEXTURE_2D);
377 return mImageArray[index.mipIndex];
378}
379
Brandon Jonescef06ff2014-08-05 13:27:48 -0700380GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700381{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700382 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
383 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700384}
385
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700386GLsizei TextureD3D_2D::getWidth(GLint level) const
387{
388 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
389 return mImageArray[level]->getWidth();
390 else
391 return 0;
392}
393
394GLsizei TextureD3D_2D::getHeight(GLint level) const
395{
396 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
397 return mImageArray[level]->getHeight();
398 else
399 return 0;
400}
401
402GLenum TextureD3D_2D::getInternalFormat(GLint level) const
403{
404 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
405 return mImageArray[level]->getInternalFormat();
406 else
407 return GL_NONE;
408}
409
410GLenum TextureD3D_2D::getActualFormat(GLint level) const
411{
412 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
413 return mImageArray[level]->getActualFormat();
414 else
415 return GL_NONE;
416}
417
418bool TextureD3D_2D::isDepth(GLint level) const
419{
Geoff Lang5d601382014-07-22 15:14:06 -0400420 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421}
422
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400423gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
424 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
425 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700426{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700427 ASSERT(target == GL_TEXTURE_2D && depth == 1);
428
Geoff Lang5d601382014-07-22 15:14:06 -0400429 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
430
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700431 bool fastUnpacked = false;
432
Brandon Jonescef06ff2014-08-05 13:27:48 -0700433 redefineImage(level, sizedInternalFormat, width, height);
434
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700435 // Attempt a fast gpu copy of the pixel data to the surface
436 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
437 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400438 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
439
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400441 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
443
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400444 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700445 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400446 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
447 if (error.isError())
448 {
449 return error;
450 }
451
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700452 // Ensure we don't overwrite our newly initialized data
453 mImageArray[level]->markClean();
454
455 fastUnpacked = true;
456 }
457 }
458
459 if (!fastUnpacked)
460 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400461 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
462 if (error.isError())
463 {
464 return error;
465 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700466 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400467
468 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700469}
470
Geoff Langb5348332014-09-02 13:16:34 -0400471gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
472 GLsizei width, GLsizei height, GLsizei depth,
473 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700474{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700475 ASSERT(target == GL_TEXTURE_2D && depth == 1);
476
477 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
478 redefineImage(level, format, width, height);
479
Geoff Langb5348332014-09-02 13:16:34 -0400480 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481}
482
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400483gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
484 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
485 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700486{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700487 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
488
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700489 bool fastUnpacked = false;
490
Jamie Madillac7579c2014-09-17 16:59:33 -0400491 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700492 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
493 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400494 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700495 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
496
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400497 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700498 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400499 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
500 if (error.isError())
501 {
502 return error;
503 }
504
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505 // Ensure we don't overwrite our newly initialized data
506 mImageArray[level]->markClean();
507
508 fastUnpacked = true;
509 }
510 }
511
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400512 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700513 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400514 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
515 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
516 pixels, index);
517 if (error.isError())
518 {
519 return error;
520 }
521
522 error = commitRect(level, xoffset, yoffset, width, height);
523 if (error.isError())
524 {
525 return error;
526 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700527 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400528
529 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700530}
531
Geoff Langb5348332014-09-02 13:16:34 -0400532gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
533 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
534 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700536 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
537
Geoff Langb5348332014-09-02 13:16:34 -0400538 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
539 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540 {
Geoff Langb5348332014-09-02 13:16:34 -0400541 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700542 }
Geoff Langb5348332014-09-02 13:16:34 -0400543
544 error = commitRect(level, xoffset, yoffset, width, height);
545 if (error.isError())
546 {
547 return error;
548 }
549
550 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700551}
552
Brandon Jonescef06ff2014-08-05 13:27:48 -0700553void 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 -0700554{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700555 ASSERT(target == GL_TEXTURE_2D);
556
557 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
558 redefineImage(level, sizedInternalFormat, width, height);
559
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700560 if (!mImageArray[level]->isRenderableFormat())
561 {
562 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
563 mDirtyImages = true;
564 }
565 else
566 {
567 ensureRenderTarget();
568 mImageArray[level]->markClean();
569
570 if (width != 0 && height != 0 && isValidLevel(level))
571 {
572 gl::Rectangle sourceRect;
573 sourceRect.x = x;
574 sourceRect.width = width;
575 sourceRect.y = y;
576 sourceRect.height = height;
577
Jamie Madill856d9d42014-09-18 15:08:49 -0400578 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579 }
580 }
581}
582
583void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
584{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700585 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
586
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
588 // the current level we're copying to is defined (with appropriate format, width & height)
589 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
590
591 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
592 {
593 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
594 mDirtyImages = true;
595 }
596 else
597 {
598 ensureRenderTarget();
599
600 if (isValidLevel(level))
601 {
602 updateStorageLevel(level);
603
604 gl::Rectangle sourceRect;
605 sourceRect.x = x;
606 sourceRect.width = width;
607 sourceRect.y = y;
608 sourceRect.height = height;
609
Jamie Madill856d9d42014-09-18 15:08:49 -0400610 mRenderer->copyImage2D(source, sourceRect,
611 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
612 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 }
614 }
615}
616
Brandon Jonescef06ff2014-08-05 13:27:48 -0700617void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700618{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700619 ASSERT(target == GL_TEXTURE_2D && depth == 1);
620
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700621 for (int level = 0; level < levels; level++)
622 {
623 GLsizei levelWidth = std::max(1, width >> level);
624 GLsizei levelHeight = std::max(1, height >> level);
625 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
626 }
627
628 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
629 {
630 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
631 }
632
633 mImmutable = true;
634
Jamie Madillc4833262014-09-18 16:18:26 -0400635 bool renderTarget = IsRenderTargetUsage(mUsage);
636 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400637 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700638}
639
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700640void TextureD3D_2D::bindTexImage(egl::Surface *surface)
641{
642 GLenum internalformat = surface->getFormat();
643
644 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
645
646 if (mTexStorage)
647 {
648 SafeDelete(mTexStorage);
649 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400650
651 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652
653 mDirtyImages = true;
654}
655
656void TextureD3D_2D::releaseTexImage()
657{
658 if (mTexStorage)
659 {
660 SafeDelete(mTexStorage);
661 }
662
663 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
664 {
665 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
666 }
667}
668
Jamie Madill4aa79e12014-09-29 10:46:14 -0400669void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700670{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700671 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700673 for (int level = 1; level < levelCount; level++)
674 {
675 redefineImage(level, getBaseLevelInternalFormat(),
676 std::max(getBaseLevelWidth() >> level, 1),
677 std::max(getBaseLevelHeight() >> level, 1));
678 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679}
680
Jamie Madillac7579c2014-09-17 16:59:33 -0400681unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700682{
Jamie Madillac7579c2014-09-17 16:59:33 -0400683 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400684 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700685}
686
Jamie Madillac7579c2014-09-17 16:59:33 -0400687RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688{
Jamie Madillac7579c2014-09-17 16:59:33 -0400689 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700690
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691 // ensure the underlying texture is created
692 if (!ensureRenderTarget())
693 {
694 return NULL;
695 }
696
Jamie Madillac7579c2014-09-17 16:59:33 -0400697 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400698 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700699}
700
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700701bool TextureD3D_2D::isValidLevel(int level) const
702{
703 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
704}
705
706bool TextureD3D_2D::isLevelComplete(int level) const
707{
708 if (isImmutable())
709 {
710 return true;
711 }
712
Brandon Jones78b1acd2014-07-15 15:33:07 -0700713 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700714
715 GLsizei width = baseImage->getWidth();
716 GLsizei height = baseImage->getHeight();
717
718 if (width <= 0 || height <= 0)
719 {
720 return false;
721 }
722
723 // The base image level is complete if the width and height are positive
724 if (level == 0)
725 {
726 return true;
727 }
728
729 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700730 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700731
732 if (image->getInternalFormat() != baseImage->getInternalFormat())
733 {
734 return false;
735 }
736
737 if (image->getWidth() != std::max(1, width >> level))
738 {
739 return false;
740 }
741
742 if (image->getHeight() != std::max(1, height >> level))
743 {
744 return false;
745 }
746
747 return true;
748}
749
750// Constructs a native texture resource from the texture images
751void TextureD3D_2D::initializeStorage(bool renderTarget)
752{
753 // Only initialize the first time this texture is used as a render target or shader resource
754 if (mTexStorage)
755 {
756 return;
757 }
758
759 // do not attempt to create storage for nonexistant data
760 if (!isLevelComplete(0))
761 {
762 return;
763 }
764
765 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
766
767 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
768 ASSERT(mTexStorage);
769
770 // flush image data to the storage
771 updateStorage();
772}
773
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400774TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700775{
776 GLsizei width = getBaseLevelWidth();
777 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400778 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700779
780 ASSERT(width > 0 && height > 0);
781
782 // use existing storage level count, when previously specified by TexStorage*D
783 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
784
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400785 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700786}
787
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400788void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700789{
790 SafeDelete(mTexStorage);
791 mTexStorage = newCompleteTexStorage;
792
793 if (mTexStorage && mTexStorage->isManaged())
794 {
795 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
796 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400797 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700798 }
799 }
800
801 mDirtyImages = true;
802}
803
804void TextureD3D_2D::updateStorage()
805{
806 ASSERT(mTexStorage != NULL);
807 GLint storageLevels = mTexStorage->getLevelCount();
808 for (int level = 0; level < storageLevels; level++)
809 {
810 if (mImageArray[level]->isDirty() && isLevelComplete(level))
811 {
812 updateStorageLevel(level);
813 }
814 }
815}
816
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700817void TextureD3D_2D::updateStorageLevel(int level)
818{
819 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
820 ASSERT(isLevelComplete(level));
821
822 if (mImageArray[level]->isDirty())
823 {
824 commitRect(level, 0, 0, getWidth(level), getHeight(level));
825 }
826}
827
828void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
829{
830 // If there currently is a corresponding storage texture image, it has these parameters
831 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
832 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
833 const GLenum storageFormat = getBaseLevelInternalFormat();
834
835 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
836
837 if (mTexStorage)
838 {
839 const int storageLevels = mTexStorage->getLevelCount();
840
841 if ((level >= storageLevels && storageLevels != 0) ||
842 width != storageWidth ||
843 height != storageHeight ||
844 internalformat != storageFormat) // Discard mismatched storage
845 {
846 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
847 {
848 mImageArray[i]->markDirty();
849 }
850
851 SafeDelete(mTexStorage);
852 mDirtyImages = true;
853 }
854 }
855}
856
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400857gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700858{
859 if (isValidLevel(level))
860 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700861 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400862 gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
863 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400865 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400867
868 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400870
871 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700872}
873
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400874gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
875{
876 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
877}
Brandon Jones0511e802014-07-14 16:27:26 -0700878
Jamie Madillcb83dc12014-09-29 10:46:12 -0400879gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
880{
881 // "layer" does not apply to 2D Textures.
882 return gl::ImageIndex::Make2D(mip);
883}
884
Brandon Jones78b1acd2014-07-15 15:33:07 -0700885TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400886 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700887{
888 for (int i = 0; i < 6; i++)
889 {
890 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
891 {
892 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
893 }
894 }
895}
896
897TextureD3D_Cube::~TextureD3D_Cube()
898{
Austin Kinross69822602014-08-12 15:51:37 -0700899 // Delete the Images before the TextureStorage.
900 // Images might be relying on the TextureStorage for some of their data.
901 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -0700902 for (int i = 0; i < 6; i++)
903 {
904 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
905 {
906 SafeDelete(mImageArray[i][j]);
907 }
908 }
Austin Kinross69822602014-08-12 15:51:37 -0700909
910 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700911}
912
Brandon Jonescef06ff2014-08-05 13:27:48 -0700913Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700914{
915 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916 ASSERT(layer < 6);
917 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700918}
919
Jamie Madillfeda4d22014-09-17 13:03:29 -0400920Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
921{
922 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
923 ASSERT(index.layerIndex < 6);
924 return mImageArray[index.layerIndex][index.mipIndex];
925}
926
Brandon Jonescef06ff2014-08-05 13:27:48 -0700927GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700928{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700929 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
930 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700931}
932
Brandon Jonescef06ff2014-08-05 13:27:48 -0700933GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700934{
935 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700936 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700937 else
938 return GL_NONE;
939}
940
Brandon Jonescef06ff2014-08-05 13:27:48 -0700941bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700942{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700943 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700944}
945
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400946gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
947 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
948 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700949{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700950 ASSERT(depth == 1);
951
952 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400953 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700954
955 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
956
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400957 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700958}
959
Geoff Langb5348332014-09-02 13:16:34 -0400960gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
961 GLsizei width, GLsizei height, GLsizei depth,
962 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700963{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700964 ASSERT(depth == 1);
965
Brandon Jones0511e802014-07-14 16:27:26 -0700966 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700967 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
968
Brandon Jones0511e802014-07-14 16:27:26 -0700969 redefineImage(faceIndex, level, format, width, height);
970
Geoff Langb5348332014-09-02 13:16:34 -0400971 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700972}
973
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400974gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
975 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
976 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700977{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700978 ASSERT(depth == 1 && zoffset == 0);
979
980 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
981
Jamie Madillfeda4d22014-09-17 13:03:29 -0400982 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400983 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
984 index);
985 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700986 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400987 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700988 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400989
990 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
991 if (error.isError())
992 {
993 return error;
994 }
995
996 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700997}
998
Geoff Langb5348332014-09-02 13:16:34 -0400999gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1000 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1001 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001002{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001003 ASSERT(depth == 1 && zoffset == 0);
1004
1005 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1006
Geoff Langb5348332014-09-02 13:16:34 -04001007 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]);
1008 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001009 {
Geoff Langb5348332014-09-02 13:16:34 -04001010 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001011 }
Geoff Langb5348332014-09-02 13:16:34 -04001012
1013 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
1014 if (error.isError())
1015 {
1016 return error;
1017 }
1018
1019 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001020}
1021
1022void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1023{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001024 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001025 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1026
Brandon Jones0511e802014-07-14 16:27:26 -07001027 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1028
1029 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1030 {
1031 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1032 mDirtyImages = true;
1033 }
1034 else
1035 {
1036 ensureRenderTarget();
1037 mImageArray[faceIndex][level]->markClean();
1038
1039 ASSERT(width == height);
1040
1041 if (width > 0 && isValidFaceLevel(faceIndex, level))
1042 {
1043 gl::Rectangle sourceRect;
1044 sourceRect.x = x;
1045 sourceRect.width = width;
1046 sourceRect.y = y;
1047 sourceRect.height = height;
1048
Jamie Madill856d9d42014-09-18 15:08:49 -04001049 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001050 }
1051 }
1052}
1053
1054void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1055{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001056 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001057
1058 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1059 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1060 // rely on the "getBaseLevel*" methods reliably otherwise.
1061 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1062
1063 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1064 {
1065 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1066 mDirtyImages = true;
1067 }
1068 else
1069 {
1070 ensureRenderTarget();
1071
1072 if (isValidFaceLevel(faceIndex, level))
1073 {
1074 updateStorageFaceLevel(faceIndex, level);
1075
1076 gl::Rectangle sourceRect;
1077 sourceRect.x = x;
1078 sourceRect.width = width;
1079 sourceRect.y = y;
1080 sourceRect.height = height;
1081
Jamie Madill856d9d42014-09-18 15:08:49 -04001082 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1083 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001084 }
1085 }
1086}
1087
Brandon Jonescef06ff2014-08-05 13:27:48 -07001088void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001089{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001090 ASSERT(width == height);
1091 ASSERT(depth == 1);
1092
Brandon Jones0511e802014-07-14 16:27:26 -07001093 for (int level = 0; level < levels; level++)
1094 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001095 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001096 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1097 {
1098 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1099 }
1100 }
1101
1102 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1103 {
1104 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1105 {
1106 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1107 }
1108 }
1109
1110 mImmutable = true;
1111
Jamie Madillc4833262014-09-18 16:18:26 -04001112 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001113 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1114 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001115}
1116
Brandon Jones0511e802014-07-14 16:27:26 -07001117// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1118bool TextureD3D_Cube::isCubeComplete() const
1119{
1120 int baseWidth = getBaseLevelWidth();
1121 int baseHeight = getBaseLevelHeight();
1122 GLenum baseFormat = getBaseLevelInternalFormat();
1123
1124 if (baseWidth <= 0 || baseWidth != baseHeight)
1125 {
1126 return false;
1127 }
1128
1129 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1130 {
1131 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1132
1133 if (faceBaseImage.getWidth() != baseWidth ||
1134 faceBaseImage.getHeight() != baseHeight ||
1135 faceBaseImage.getInternalFormat() != baseFormat )
1136 {
1137 return false;
1138 }
1139 }
1140
1141 return true;
1142}
1143
Brandon Jones6053a522014-07-25 16:22:09 -07001144void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1145{
1146 UNREACHABLE();
1147}
1148
1149void TextureD3D_Cube::releaseTexImage()
1150{
1151 UNREACHABLE();
1152}
1153
1154
Jamie Madill4aa79e12014-09-29 10:46:14 -04001155void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001156{
1157 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1158 int levelCount = mipLevels();
1159 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1160 {
1161 for (int level = 1; level < levelCount; level++)
1162 {
1163 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1164 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1165 }
1166 }
Brandon Jones0511e802014-07-14 16:27:26 -07001167}
1168
Jamie Madillac7579c2014-09-17 16:59:33 -04001169unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
Jamie Madillc4833262014-09-18 16:18:26 -04001171 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001172}
1173
Jamie Madillac7579c2014-09-17 16:59:33 -04001174RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001175{
Jamie Madillac7579c2014-09-17 16:59:33 -04001176 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001177
1178 // ensure the underlying texture is created
1179 if (!ensureRenderTarget())
1180 {
1181 return NULL;
1182 }
1183
Jamie Madillac7579c2014-09-17 16:59:33 -04001184 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001185 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001186}
1187
Brandon Jones0511e802014-07-14 16:27:26 -07001188void TextureD3D_Cube::initializeStorage(bool renderTarget)
1189{
1190 // Only initialize the first time this texture is used as a render target or shader resource
1191 if (mTexStorage)
1192 {
1193 return;
1194 }
1195
1196 // do not attempt to create storage for nonexistant data
1197 if (!isFaceLevelComplete(0, 0))
1198 {
1199 return;
1200 }
1201
1202 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1203
1204 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1205 ASSERT(mTexStorage);
1206
1207 // flush image data to the storage
1208 updateStorage();
1209}
1210
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001211TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001212{
1213 GLsizei size = getBaseLevelWidth();
1214
1215 ASSERT(size > 0);
1216
1217 // use existing storage level count, when previously specified by TexStorage*D
1218 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1219
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001220 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001221}
1222
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001223void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001224{
1225 SafeDelete(mTexStorage);
1226 mTexStorage = newCompleteTexStorage;
1227
1228 if (mTexStorage && mTexStorage->isManaged())
1229 {
1230 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1231 {
1232 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1233 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001234 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001235 }
1236 }
1237 }
1238
1239 mDirtyImages = true;
1240}
1241
1242void TextureD3D_Cube::updateStorage()
1243{
1244 ASSERT(mTexStorage != NULL);
1245 GLint storageLevels = mTexStorage->getLevelCount();
1246 for (int face = 0; face < 6; face++)
1247 {
1248 for (int level = 0; level < storageLevels; level++)
1249 {
1250 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1251 {
1252 updateStorageFaceLevel(face, level);
1253 }
1254 }
1255 }
1256}
1257
Brandon Jones0511e802014-07-14 16:27:26 -07001258bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1259{
1260 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1261}
1262
Brandon Jones0511e802014-07-14 16:27:26 -07001263bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1264{
1265 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1266
1267 if (isImmutable())
1268 {
1269 return true;
1270 }
1271
1272 int baseSize = getBaseLevelWidth();
1273
1274 if (baseSize <= 0)
1275 {
1276 return false;
1277 }
1278
1279 // "isCubeComplete" checks for base level completeness and we must call that
1280 // to determine if any face at level 0 is complete. We omit that check here
1281 // to avoid re-checking cube-completeness for every face at level 0.
1282 if (level == 0)
1283 {
1284 return true;
1285 }
1286
1287 // Check that non-zero levels are consistent with the base level.
1288 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1289
1290 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1291 {
1292 return false;
1293 }
1294
1295 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1296 {
1297 return false;
1298 }
1299
1300 return true;
1301}
1302
1303void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1304{
1305 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1306 ImageD3D *image = mImageArray[faceIndex][level];
1307
1308 if (image->isDirty())
1309 {
1310 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1311 }
1312}
1313
1314void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1315{
1316 // If there currently is a corresponding storage texture image, it has these parameters
1317 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1318 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1319 const GLenum storageFormat = getBaseLevelInternalFormat();
1320
1321 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1322
1323 if (mTexStorage)
1324 {
1325 const int storageLevels = mTexStorage->getLevelCount();
1326
1327 if ((level >= storageLevels && storageLevels != 0) ||
1328 width != storageWidth ||
1329 height != storageHeight ||
1330 internalformat != storageFormat) // Discard mismatched storage
1331 {
1332 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1333 {
1334 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1335 {
1336 mImageArray[faceIndex][level]->markDirty();
1337 }
1338 }
1339
1340 SafeDelete(mTexStorage);
1341
1342 mDirtyImages = true;
1343 }
1344 }
1345}
1346
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001347gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jones0511e802014-07-14 16:27:26 -07001348{
1349 if (isValidFaceLevel(faceIndex, level))
1350 {
1351 ImageD3D *image = mImageArray[faceIndex][level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001352 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
1353 if (error.isError())
1354 {
1355 return error;
1356 }
1357
1358 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001359 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001360
1361 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001362}
1363
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001364gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1365{
1366 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1367}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001368
Jamie Madillcb83dc12014-09-29 10:46:12 -04001369gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1370{
1371 // The "layer" of the image index corresponds to the cube face
1372 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1373}
1374
Brandon Jones78b1acd2014-07-15 15:33:07 -07001375TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001376 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001377{
1378 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1379 {
1380 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1381 }
1382}
1383
1384TextureD3D_3D::~TextureD3D_3D()
1385{
Austin Kinross69822602014-08-12 15:51:37 -07001386 // Delete the Images before the TextureStorage.
1387 // Images might be relying on the TextureStorage for some of their data.
1388 // 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 -07001389 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1390 {
1391 delete mImageArray[i];
1392 }
Austin Kinross69822602014-08-12 15:51:37 -07001393
1394 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001395}
1396
Brandon Jonescef06ff2014-08-05 13:27:48 -07001397Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001398{
1399 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001400 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001401 return mImageArray[level];
1402}
1403
Jamie Madillfeda4d22014-09-17 13:03:29 -04001404Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1405{
1406 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001407 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001408 ASSERT(index.type == GL_TEXTURE_3D);
1409 return mImageArray[index.mipIndex];
1410}
1411
Brandon Jonescef06ff2014-08-05 13:27:48 -07001412GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001414 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1415 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001416}
1417
Brandon Jones78b1acd2014-07-15 15:33:07 -07001418GLsizei TextureD3D_3D::getWidth(GLint level) const
1419{
1420 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1421 return mImageArray[level]->getWidth();
1422 else
1423 return 0;
1424}
1425
1426GLsizei TextureD3D_3D::getHeight(GLint level) const
1427{
1428 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1429 return mImageArray[level]->getHeight();
1430 else
1431 return 0;
1432}
1433
1434GLsizei TextureD3D_3D::getDepth(GLint level) const
1435{
1436 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1437 return mImageArray[level]->getDepth();
1438 else
1439 return 0;
1440}
1441
1442GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1443{
1444 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1445 return mImageArray[level]->getInternalFormat();
1446 else
1447 return GL_NONE;
1448}
1449
1450bool TextureD3D_3D::isDepth(GLint level) const
1451{
Geoff Lang5d601382014-07-22 15:14:06 -04001452 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001453}
1454
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001455gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1456 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1457 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001458{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001459 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001460 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1461
Brandon Jones78b1acd2014-07-15 15:33:07 -07001462 redefineImage(level, sizedInternalFormat, width, height, depth);
1463
1464 bool fastUnpacked = false;
1465
1466 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1467 if (isFastUnpackable(unpack, sizedInternalFormat))
1468 {
1469 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001470 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1471 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001472 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1473
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001474 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001475 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001476 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1477 if (error.isError())
1478 {
1479 return error;
1480 }
1481
Brandon Jones78b1acd2014-07-15 15:33:07 -07001482 // Ensure we don't overwrite our newly initialized data
1483 mImageArray[level]->markClean();
1484
1485 fastUnpacked = true;
1486 }
1487 }
1488
1489 if (!fastUnpacked)
1490 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001491 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1492 if (error.isError())
1493 {
1494 return error;
1495 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001496 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001497
1498 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001499}
1500
Geoff Langb5348332014-09-02 13:16:34 -04001501gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1502 GLsizei width, GLsizei height,GLsizei depth,
1503 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001504{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001505 ASSERT(target == GL_TEXTURE_3D);
1506
Brandon Jones78b1acd2014-07-15 15:33:07 -07001507 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1508 redefineImage(level, format, width, height, depth);
1509
Geoff Langb5348332014-09-02 13:16:34 -04001510 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511}
1512
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001513gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1514 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1515 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001516{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001517 ASSERT(target == GL_TEXTURE_3D);
1518
Brandon Jones78b1acd2014-07-15 15:33:07 -07001519 bool fastUnpacked = false;
1520
Jamie Madillac7579c2014-09-17 16:59:33 -04001521 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1522
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1524 if (isFastUnpackable(unpack, getInternalFormat(level)))
1525 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001526 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001527 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1528
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001529 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001530 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001531 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1532 if (error.isError())
1533 {
1534 return error;
1535 }
1536
Brandon Jones78b1acd2014-07-15 15:33:07 -07001537 // Ensure we don't overwrite our newly initialized data
1538 mImageArray[level]->markClean();
1539
1540 fastUnpacked = true;
1541 }
1542 }
1543
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001544 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001545 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001546 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1547 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1548 pixels, index);
1549 if (error.isError())
1550 {
1551 return error;
1552 }
1553
1554 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1555 if (error.isError())
1556 {
1557 return error;
1558 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001559 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001560
1561 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001562}
1563
Geoff Langb5348332014-09-02 13:16:34 -04001564gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1565 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1566 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001567{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001568 ASSERT(target == GL_TEXTURE_3D);
1569
Geoff Langb5348332014-09-02 13:16:34 -04001570 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1571 format, imageSize, pixels, mImageArray[level]);
1572 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001573 {
Geoff Langb5348332014-09-02 13:16:34 -04001574 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001575 }
Geoff Langb5348332014-09-02 13:16:34 -04001576
1577 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1578 if (error.isError())
1579 {
1580 return error;
1581 }
1582
1583 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001584}
1585
Brandon Jonescef06ff2014-08-05 13:27:48 -07001586void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1587{
1588 UNIMPLEMENTED();
1589}
1590
Brandon Jones78b1acd2014-07-15 15:33:07 -07001591void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1592{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001593 ASSERT(target == GL_TEXTURE_3D);
1594
Brandon Jones78b1acd2014-07-15 15:33:07 -07001595 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1596 // the current level we're copying to is defined (with appropriate format, width & height)
1597 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1598
1599 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1600 {
1601 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1602 mDirtyImages = true;
1603 }
1604 else
1605 {
1606 ensureRenderTarget();
1607
1608 if (isValidLevel(level))
1609 {
1610 updateStorageLevel(level);
1611
1612 gl::Rectangle sourceRect;
1613 sourceRect.x = x;
1614 sourceRect.width = width;
1615 sourceRect.y = y;
1616 sourceRect.height = height;
1617
Jamie Madill856d9d42014-09-18 15:08:49 -04001618 mRenderer->copyImage3D(source, sourceRect,
1619 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1620 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001621 }
1622 }
1623}
1624
Brandon Jonescef06ff2014-08-05 13:27:48 -07001625void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001627 ASSERT(target == GL_TEXTURE_3D);
1628
Brandon Jones78b1acd2014-07-15 15:33:07 -07001629 for (int level = 0; level < levels; level++)
1630 {
1631 GLsizei levelWidth = std::max(1, width >> level);
1632 GLsizei levelHeight = std::max(1, height >> level);
1633 GLsizei levelDepth = std::max(1, depth >> level);
1634 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1635 }
1636
1637 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1638 {
1639 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1640 }
1641
1642 mImmutable = true;
1643
Jamie Madillc4833262014-09-18 16:18:26 -04001644 bool renderTarget = IsRenderTargetUsage(mUsage);
1645 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001646 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001647}
1648
Brandon Jones6053a522014-07-25 16:22:09 -07001649void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001650{
Brandon Jones6053a522014-07-25 16:22:09 -07001651 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652}
1653
Brandon Jones6053a522014-07-25 16:22:09 -07001654void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001655{
Brandon Jones6053a522014-07-25 16:22:09 -07001656 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001657}
1658
Brandon Jones6053a522014-07-25 16:22:09 -07001659
Jamie Madill4aa79e12014-09-29 10:46:14 -04001660void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001661{
1662 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1663 int levelCount = mipLevels();
1664 for (int level = 1; level < levelCount; level++)
1665 {
1666 redefineImage(level, getBaseLevelInternalFormat(),
1667 std::max(getBaseLevelWidth() >> level, 1),
1668 std::max(getBaseLevelHeight() >> level, 1),
1669 std::max(getBaseLevelDepth() >> level, 1));
1670 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001671}
1672
Jamie Madillac7579c2014-09-17 16:59:33 -04001673unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674{
Jamie Madillc4833262014-09-18 16:18:26 -04001675 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001676}
1677
Jamie Madillac7579c2014-09-17 16:59:33 -04001678RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001679{
1680 // ensure the underlying texture is created
1681 if (!ensureRenderTarget())
1682 {
1683 return NULL;
1684 }
1685
Jamie Madillac7579c2014-09-17 16:59:33 -04001686 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001687 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001688 updateStorage();
1689 }
1690 else
1691 {
1692 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001693 }
1694
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001695 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001696}
1697
1698void TextureD3D_3D::initializeStorage(bool renderTarget)
1699{
1700 // Only initialize the first time this texture is used as a render target or shader resource
1701 if (mTexStorage)
1702 {
1703 return;
1704 }
1705
1706 // do not attempt to create storage for nonexistant data
1707 if (!isLevelComplete(0))
1708 {
1709 return;
1710 }
1711
1712 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1713
1714 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1715 ASSERT(mTexStorage);
1716
1717 // flush image data to the storage
1718 updateStorage();
1719}
1720
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001721TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001722{
1723 GLsizei width = getBaseLevelWidth();
1724 GLsizei height = getBaseLevelHeight();
1725 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001726 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001727
1728 ASSERT(width > 0 && height > 0 && depth > 0);
1729
1730 // use existing storage level count, when previously specified by TexStorage*D
1731 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1732
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001733 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001734}
1735
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001736void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737{
1738 SafeDelete(mTexStorage);
1739 mTexStorage = newCompleteTexStorage;
1740 mDirtyImages = true;
1741
1742 // We do not support managed 3D storage, as that is D3D9/ES2-only
1743 ASSERT(!mTexStorage->isManaged());
1744}
1745
1746void TextureD3D_3D::updateStorage()
1747{
1748 ASSERT(mTexStorage != NULL);
1749 GLint storageLevels = mTexStorage->getLevelCount();
1750 for (int level = 0; level < storageLevels; level++)
1751 {
1752 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1753 {
1754 updateStorageLevel(level);
1755 }
1756 }
1757}
1758
Brandon Jones78b1acd2014-07-15 15:33:07 -07001759bool TextureD3D_3D::isValidLevel(int level) const
1760{
1761 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1762}
1763
1764bool TextureD3D_3D::isLevelComplete(int level) const
1765{
1766 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1767
1768 if (isImmutable())
1769 {
1770 return true;
1771 }
1772
1773 GLsizei width = getBaseLevelWidth();
1774 GLsizei height = getBaseLevelHeight();
1775 GLsizei depth = getBaseLevelDepth();
1776
1777 if (width <= 0 || height <= 0 || depth <= 0)
1778 {
1779 return false;
1780 }
1781
1782 if (level == 0)
1783 {
1784 return true;
1785 }
1786
1787 ImageD3D *levelImage = mImageArray[level];
1788
1789 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1790 {
1791 return false;
1792 }
1793
1794 if (levelImage->getWidth() != std::max(1, width >> level))
1795 {
1796 return false;
1797 }
1798
1799 if (levelImage->getHeight() != std::max(1, height >> level))
1800 {
1801 return false;
1802 }
1803
1804 if (levelImage->getDepth() != std::max(1, depth >> level))
1805 {
1806 return false;
1807 }
1808
1809 return true;
1810}
1811
1812void TextureD3D_3D::updateStorageLevel(int level)
1813{
1814 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1815 ASSERT(isLevelComplete(level));
1816
1817 if (mImageArray[level]->isDirty())
1818 {
1819 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1820 }
1821}
1822
1823void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1824{
1825 // If there currently is a corresponding storage texture image, it has these parameters
1826 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1827 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1828 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1829 const GLenum storageFormat = getBaseLevelInternalFormat();
1830
1831 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1832
1833 if (mTexStorage)
1834 {
1835 const int storageLevels = mTexStorage->getLevelCount();
1836
1837 if ((level >= storageLevels && storageLevels != 0) ||
1838 width != storageWidth ||
1839 height != storageHeight ||
1840 depth != storageDepth ||
1841 internalformat != storageFormat) // Discard mismatched storage
1842 {
1843 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1844 {
1845 mImageArray[i]->markDirty();
1846 }
1847
1848 SafeDelete(mTexStorage);
1849 mDirtyImages = true;
1850 }
1851 }
1852}
1853
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001854gl::Error TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855{
1856 if (isValidLevel(level))
1857 {
1858 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001859 gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
1860 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001862 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001864
1865 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001866 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001867
1868 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001869}
1870
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001871gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1872{
1873 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1874 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1875}
Brandon Jones142ec422014-07-16 10:31:30 -07001876
Jamie Madillcb83dc12014-09-29 10:46:12 -04001877gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1878{
1879 // The "layer" here does not apply to 3D images. We use one Image per mip.
1880 return gl::ImageIndex::Make3D(mip);
1881}
1882
Brandon Jones142ec422014-07-16 10:31:30 -07001883TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001884 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001885{
1886 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1887 {
1888 mLayerCounts[level] = 0;
1889 mImageArray[level] = NULL;
1890 }
1891}
1892
1893TextureD3D_2DArray::~TextureD3D_2DArray()
1894{
Austin Kinross69822602014-08-12 15:51:37 -07001895 // Delete the Images before the TextureStorage.
1896 // Images might be relying on the TextureStorage for some of their data.
1897 // 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 -07001898 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001899 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001900}
1901
Brandon Jones142ec422014-07-16 10:31:30 -07001902Image *TextureD3D_2DArray::getImage(int level, int layer) const
1903{
1904 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1905 ASSERT(layer < mLayerCounts[level]);
1906 return mImageArray[level][layer];
1907}
1908
Jamie Madillfeda4d22014-09-17 13:03:29 -04001909Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1910{
1911 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1912 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1913 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1914 return mImageArray[index.mipIndex][index.layerIndex];
1915}
1916
Brandon Jones142ec422014-07-16 10:31:30 -07001917GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1918{
1919 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1920 return mLayerCounts[level];
1921}
1922
Brandon Jones142ec422014-07-16 10:31:30 -07001923GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1924{
1925 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1926}
1927
1928GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1929{
1930 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1931}
1932
Brandon Jones142ec422014-07-16 10:31:30 -07001933GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1934{
1935 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1936}
1937
1938bool TextureD3D_2DArray::isDepth(GLint level) const
1939{
Geoff Lang5d601382014-07-22 15:14:06 -04001940 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001941}
1942
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001943gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1944 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1945 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001946{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001947 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1948
Geoff Lang5d601382014-07-22 15:14:06 -04001949 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1950
Brandon Jones142ec422014-07-16 10:31:30 -07001951 redefineImage(level, sizedInternalFormat, width, height, depth);
1952
Geoff Lang5d601382014-07-22 15:14:06 -04001953 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1954 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001955
1956 for (int i = 0; i < depth; i++)
1957 {
1958 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001959 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1960 if (error.isError())
1961 {
1962 return error;
1963 }
Brandon Jones142ec422014-07-16 10:31:30 -07001964 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001965
1966 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001967}
1968
Geoff Langb5348332014-09-02 13:16:34 -04001969gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1970 GLsizei width, GLsizei height, GLsizei depth,
1971 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001972{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001973 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1974
Brandon Jones142ec422014-07-16 10:31:30 -07001975 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1976 redefineImage(level, format, width, height, depth);
1977
Geoff Lang5d601382014-07-22 15:14:06 -04001978 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1979 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001980
1981 for (int i = 0; i < depth; i++)
1982 {
1983 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001984 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1985 if (error.isError())
1986 {
1987 return error;
1988 }
Brandon Jones142ec422014-07-16 10:31:30 -07001989 }
Geoff Langb5348332014-09-02 13:16:34 -04001990
1991 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001992}
1993
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001994gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1995 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1996 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001997{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001998 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1999
Geoff Lang5d601382014-07-22 15:14:06 -04002000 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2001 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002002
2003 for (int i = 0; i < depth; i++)
2004 {
2005 int layer = zoffset + i;
2006 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2007
Jamie Madillfeda4d22014-09-17 13:03:29 -04002008 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002009 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2010 layerPixels, index);
2011 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002012 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002013 return error;
2014 }
2015
2016 error = commitRect(level, xoffset, yoffset, layer, width, height);
2017 if (error.isError())
2018 {
2019 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002020 }
2021 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002022
2023 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002024}
2025
Geoff Langb5348332014-09-02 13:16:34 -04002026gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2027 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2028 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002029{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002030 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2031
Geoff Lang5d601382014-07-22 15:14:06 -04002032 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2033 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002034
2035 for (int i = 0; i < depth; i++)
2036 {
2037 int layer = zoffset + i;
2038 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2039
Geoff Langb5348332014-09-02 13:16:34 -04002040 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2041 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002042 {
Geoff Langb5348332014-09-02 13:16:34 -04002043 return error;
2044 }
2045
2046 error = commitRect(level, xoffset, yoffset, layer, width, height);
2047 if (error.isError())
2048 {
2049 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002050 }
2051 }
Geoff Langb5348332014-09-02 13:16:34 -04002052
2053 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002054}
2055
Brandon Jonescef06ff2014-08-05 13:27:48 -07002056void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2057{
2058 UNIMPLEMENTED();
2059}
2060
Brandon Jones142ec422014-07-16 10:31:30 -07002061void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2062{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002063 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2064
Brandon Jones142ec422014-07-16 10:31:30 -07002065 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2066 // the current level we're copying to is defined (with appropriate format, width & height)
2067 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2068
2069 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2070 {
2071 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2072 mDirtyImages = true;
2073 }
2074 else
2075 {
2076 ensureRenderTarget();
2077
2078 if (isValidLevel(level))
2079 {
2080 updateStorageLevel(level);
2081
2082 gl::Rectangle sourceRect;
2083 sourceRect.x = x;
2084 sourceRect.width = width;
2085 sourceRect.y = y;
2086 sourceRect.height = height;
2087
Jamie Madill856d9d42014-09-18 15:08:49 -04002088 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2089 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002090 }
2091 }
2092}
2093
Brandon Jonescef06ff2014-08-05 13:27:48 -07002094void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002095{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002096 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2097
Brandon Jones142ec422014-07-16 10:31:30 -07002098 deleteImages();
2099
2100 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2101 {
2102 GLsizei levelWidth = std::max(1, width >> level);
2103 GLsizei levelHeight = std::max(1, height >> level);
2104
2105 mLayerCounts[level] = (level < levels ? depth : 0);
2106
2107 if (mLayerCounts[level] > 0)
2108 {
2109 // Create new images for this level
2110 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2111
2112 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2113 {
2114 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2115 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2116 levelHeight, 1, true);
2117 }
2118 }
2119 }
2120
2121 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002122
2123 bool renderTarget = IsRenderTargetUsage(mUsage);
2124 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002125 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002126}
2127
Brandon Jones6053a522014-07-25 16:22:09 -07002128void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002129{
Brandon Jones6053a522014-07-25 16:22:09 -07002130 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002131}
2132
Brandon Jones6053a522014-07-25 16:22:09 -07002133void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002134{
Brandon Jones6053a522014-07-25 16:22:09 -07002135 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002136}
2137
Brandon Jones6053a522014-07-25 16:22:09 -07002138
Jamie Madill4aa79e12014-09-29 10:46:14 -04002139void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002140{
2141 int baseWidth = getBaseLevelWidth();
2142 int baseHeight = getBaseLevelHeight();
2143 int baseDepth = getBaseLevelDepth();
2144 GLenum baseFormat = getBaseLevelInternalFormat();
2145
2146 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2147 int levelCount = mipLevels();
2148 for (int level = 1; level < levelCount; level++)
2149 {
2150 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2151 }
Brandon Jones142ec422014-07-16 10:31:30 -07002152}
2153
Jamie Madillac7579c2014-09-17 16:59:33 -04002154unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002155{
Jamie Madillc4833262014-09-18 16:18:26 -04002156 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002157}
2158
Jamie Madillac7579c2014-09-17 16:59:33 -04002159RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002160{
2161 // ensure the underlying texture is created
2162 if (!ensureRenderTarget())
2163 {
2164 return NULL;
2165 }
2166
Jamie Madillac7579c2014-09-17 16:59:33 -04002167 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002168 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002169}
2170
2171void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2172{
2173 // Only initialize the first time this texture is used as a render target or shader resource
2174 if (mTexStorage)
2175 {
2176 return;
2177 }
2178
2179 // do not attempt to create storage for nonexistant data
2180 if (!isLevelComplete(0))
2181 {
2182 return;
2183 }
2184
2185 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2186
2187 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2188 ASSERT(mTexStorage);
2189
2190 // flush image data to the storage
2191 updateStorage();
2192}
2193
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002194TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002195{
2196 GLsizei width = getBaseLevelWidth();
2197 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002198 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002199 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002200
2201 ASSERT(width > 0 && height > 0 && depth > 0);
2202
2203 // use existing storage level count, when previously specified by TexStorage*D
2204 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2205
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002206 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002207}
2208
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002209void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002210{
2211 SafeDelete(mTexStorage);
2212 mTexStorage = newCompleteTexStorage;
2213 mDirtyImages = true;
2214
2215 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2216 ASSERT(!mTexStorage->isManaged());
2217}
2218
2219void TextureD3D_2DArray::updateStorage()
2220{
2221 ASSERT(mTexStorage != NULL);
2222 GLint storageLevels = mTexStorage->getLevelCount();
2223 for (int level = 0; level < storageLevels; level++)
2224 {
2225 if (isLevelComplete(level))
2226 {
2227 updateStorageLevel(level);
2228 }
2229 }
2230}
2231
Brandon Jones142ec422014-07-16 10:31:30 -07002232bool TextureD3D_2DArray::isValidLevel(int level) const
2233{
2234 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2235}
2236
2237bool TextureD3D_2DArray::isLevelComplete(int level) const
2238{
2239 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2240
2241 if (isImmutable())
2242 {
2243 return true;
2244 }
2245
2246 GLsizei width = getBaseLevelWidth();
2247 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002248 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002249
2250 if (width <= 0 || height <= 0 || layers <= 0)
2251 {
2252 return false;
2253 }
2254
2255 if (level == 0)
2256 {
2257 return true;
2258 }
2259
2260 if (getInternalFormat(level) != getInternalFormat(0))
2261 {
2262 return false;
2263 }
2264
2265 if (getWidth(level) != std::max(1, width >> level))
2266 {
2267 return false;
2268 }
2269
2270 if (getHeight(level) != std::max(1, height >> level))
2271 {
2272 return false;
2273 }
2274
Jamie Madill3269bcb2014-09-30 16:33:52 -04002275 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002276 {
2277 return false;
2278 }
2279
2280 return true;
2281}
2282
2283void TextureD3D_2DArray::updateStorageLevel(int level)
2284{
2285 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2286 ASSERT(isLevelComplete(level));
2287
2288 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2289 {
2290 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2291 if (mImageArray[level][layer]->isDirty())
2292 {
2293 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2294 }
2295 }
2296}
2297
2298void TextureD3D_2DArray::deleteImages()
2299{
2300 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2301 {
2302 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2303 {
2304 delete mImageArray[level][layer];
2305 }
2306 delete[] mImageArray[level];
2307 mImageArray[level] = NULL;
2308 mLayerCounts[level] = 0;
2309 }
2310}
2311
2312void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2313{
2314 // If there currently is a corresponding storage texture image, it has these parameters
2315 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2316 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002317 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002318 const GLenum storageFormat = getBaseLevelInternalFormat();
2319
2320 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2321 {
2322 delete mImageArray[level][layer];
2323 }
2324 delete[] mImageArray[level];
2325 mImageArray[level] = NULL;
2326 mLayerCounts[level] = depth;
2327
2328 if (depth > 0)
2329 {
2330 mImageArray[level] = new ImageD3D*[depth]();
2331
2332 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2333 {
2334 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2335 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2336 }
2337 }
2338
2339 if (mTexStorage)
2340 {
2341 const int storageLevels = mTexStorage->getLevelCount();
2342
2343 if ((level >= storageLevels && storageLevels != 0) ||
2344 width != storageWidth ||
2345 height != storageHeight ||
2346 depth != storageDepth ||
2347 internalformat != storageFormat) // Discard mismatched storage
2348 {
2349 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2350 {
2351 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2352 {
2353 mImageArray[level][layer]->markDirty();
2354 }
2355 }
2356
2357 delete mTexStorage;
2358 mTexStorage = NULL;
2359 mDirtyImages = true;
2360 }
2361 }
2362}
2363
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002364gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
Brandon Jones142ec422014-07-16 10:31:30 -07002365{
Jamie Madill3269bcb2014-09-30 16:33:52 -04002366 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002367 {
2368 ImageD3D *image = mImageArray[level][layerTarget];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002369 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
2370 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002371 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002372 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002373 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002374
2375 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002376 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002377
2378 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002379}
2380
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002381gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2382{
2383 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2384}
2385
Jamie Madillcb83dc12014-09-29 10:46:12 -04002386gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2387{
2388 return gl::ImageIndex::Make2DArray(mip, layer);
2389}
2390
Brandon Jones78b1acd2014-07-15 15:33:07 -07002391}