blob: b67261738a7471a56e467fbc6303ed6ff389ca48 [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);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400492 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
494 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400495 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700496
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::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
515 pixels, index);
516 if (error.isError())
517 {
518 return error;
519 }
520
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400521 error = commitRegion(index, destArea);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400522 if (error.isError())
523 {
524 return error;
525 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700526 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400527
528 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700529}
530
Geoff Langb5348332014-09-02 13:16:34 -0400531gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
532 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
533 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700535 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
536
Geoff Langb5348332014-09-02 13:16:34 -0400537 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
538 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700539 {
Geoff Langb5348332014-09-02 13:16:34 -0400540 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700541 }
Geoff Langb5348332014-09-02 13:16:34 -0400542
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400543 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
544 gl::Box region(xoffset, yoffset, 0, width, height, 1);
545 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700546}
547
Brandon Jonescef06ff2014-08-05 13:27:48 -0700548void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700549{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700550 ASSERT(target == GL_TEXTURE_2D);
551
552 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
553 redefineImage(level, sizedInternalFormat, width, height);
554
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555 if (!mImageArray[level]->isRenderableFormat())
556 {
557 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
558 mDirtyImages = true;
559 }
560 else
561 {
562 ensureRenderTarget();
563 mImageArray[level]->markClean();
564
565 if (width != 0 && height != 0 && isValidLevel(level))
566 {
567 gl::Rectangle sourceRect;
568 sourceRect.x = x;
569 sourceRect.width = width;
570 sourceRect.y = y;
571 sourceRect.height = height;
572
Jamie Madill856d9d42014-09-18 15:08:49 -0400573 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700574 }
575 }
576}
577
578void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
579{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700580 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
581
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
583 // the current level we're copying to is defined (with appropriate format, width & height)
584 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
585
586 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
587 {
588 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
589 mDirtyImages = true;
590 }
591 else
592 {
593 ensureRenderTarget();
594
595 if (isValidLevel(level))
596 {
597 updateStorageLevel(level);
598
599 gl::Rectangle sourceRect;
600 sourceRect.x = x;
601 sourceRect.width = width;
602 sourceRect.y = y;
603 sourceRect.height = height;
604
Jamie Madill856d9d42014-09-18 15:08:49 -0400605 mRenderer->copyImage2D(source, sourceRect,
606 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
607 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608 }
609 }
610}
611
Brandon Jonescef06ff2014-08-05 13:27:48 -0700612void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700614 ASSERT(target == GL_TEXTURE_2D && depth == 1);
615
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 for (int level = 0; level < levels; level++)
617 {
618 GLsizei levelWidth = std::max(1, width >> level);
619 GLsizei levelHeight = std::max(1, height >> level);
620 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
621 }
622
623 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
624 {
625 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
626 }
627
628 mImmutable = true;
629
Jamie Madillc4833262014-09-18 16:18:26 -0400630 bool renderTarget = IsRenderTargetUsage(mUsage);
631 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400632 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700633}
634
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635void TextureD3D_2D::bindTexImage(egl::Surface *surface)
636{
637 GLenum internalformat = surface->getFormat();
638
639 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
640
641 if (mTexStorage)
642 {
643 SafeDelete(mTexStorage);
644 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400645
646 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700647
648 mDirtyImages = true;
649}
650
651void TextureD3D_2D::releaseTexImage()
652{
653 if (mTexStorage)
654 {
655 SafeDelete(mTexStorage);
656 }
657
658 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
659 {
660 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
661 }
662}
663
Jamie Madill4aa79e12014-09-29 10:46:14 -0400664void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700666 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700668 for (int level = 1; level < levelCount; level++)
669 {
670 redefineImage(level, getBaseLevelInternalFormat(),
671 std::max(getBaseLevelWidth() >> level, 1),
672 std::max(getBaseLevelHeight() >> level, 1));
673 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674}
675
Jamie Madillac7579c2014-09-17 16:59:33 -0400676unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677{
Jamie Madillac7579c2014-09-17 16:59:33 -0400678 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400679 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700680}
681
Jamie Madillac7579c2014-09-17 16:59:33 -0400682RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683{
Jamie Madillac7579c2014-09-17 16:59:33 -0400684 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700685
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 // ensure the underlying texture is created
687 if (!ensureRenderTarget())
688 {
689 return NULL;
690 }
691
Jamie Madillac7579c2014-09-17 16:59:33 -0400692 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400693 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694}
695
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700696bool TextureD3D_2D::isValidLevel(int level) const
697{
698 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
699}
700
701bool TextureD3D_2D::isLevelComplete(int level) const
702{
703 if (isImmutable())
704 {
705 return true;
706 }
707
Brandon Jones78b1acd2014-07-15 15:33:07 -0700708 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700709
710 GLsizei width = baseImage->getWidth();
711 GLsizei height = baseImage->getHeight();
712
713 if (width <= 0 || height <= 0)
714 {
715 return false;
716 }
717
718 // The base image level is complete if the width and height are positive
719 if (level == 0)
720 {
721 return true;
722 }
723
724 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700725 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700726
727 if (image->getInternalFormat() != baseImage->getInternalFormat())
728 {
729 return false;
730 }
731
732 if (image->getWidth() != std::max(1, width >> level))
733 {
734 return false;
735 }
736
737 if (image->getHeight() != std::max(1, height >> level))
738 {
739 return false;
740 }
741
742 return true;
743}
744
745// Constructs a native texture resource from the texture images
746void TextureD3D_2D::initializeStorage(bool renderTarget)
747{
748 // Only initialize the first time this texture is used as a render target or shader resource
749 if (mTexStorage)
750 {
751 return;
752 }
753
754 // do not attempt to create storage for nonexistant data
755 if (!isLevelComplete(0))
756 {
757 return;
758 }
759
760 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
761
762 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
763 ASSERT(mTexStorage);
764
765 // flush image data to the storage
766 updateStorage();
767}
768
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400769TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770{
771 GLsizei width = getBaseLevelWidth();
772 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400773 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700774
775 ASSERT(width > 0 && height > 0);
776
777 // use existing storage level count, when previously specified by TexStorage*D
778 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
779
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400780 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700781}
782
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400783void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700784{
785 SafeDelete(mTexStorage);
786 mTexStorage = newCompleteTexStorage;
787
788 if (mTexStorage && mTexStorage->isManaged())
789 {
790 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
791 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400792 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793 }
794 }
795
796 mDirtyImages = true;
797}
798
799void TextureD3D_2D::updateStorage()
800{
801 ASSERT(mTexStorage != NULL);
802 GLint storageLevels = mTexStorage->getLevelCount();
803 for (int level = 0; level < storageLevels; level++)
804 {
805 if (mImageArray[level]->isDirty() && isLevelComplete(level))
806 {
807 updateStorageLevel(level);
808 }
809 }
810}
811
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812void TextureD3D_2D::updateStorageLevel(int level)
813{
814 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
815 ASSERT(isLevelComplete(level));
816
817 if (mImageArray[level]->isDirty())
818 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400819 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
820 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
821 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700822 }
823}
824
825void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
826{
827 // If there currently is a corresponding storage texture image, it has these parameters
828 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
829 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
830 const GLenum storageFormat = getBaseLevelInternalFormat();
831
832 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
833
834 if (mTexStorage)
835 {
836 const int storageLevels = mTexStorage->getLevelCount();
837
838 if ((level >= storageLevels && storageLevels != 0) ||
839 width != storageWidth ||
840 height != storageHeight ||
841 internalformat != storageFormat) // Discard mismatched storage
842 {
843 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
844 {
845 mImageArray[i]->markDirty();
846 }
847
848 SafeDelete(mTexStorage);
849 mDirtyImages = true;
850 }
851 }
852}
853
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400854gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700855{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400856 ASSERT(!index.hasLayer());
857 GLint level = index.mipIndex;
858
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700859 if (isValidLevel(level))
860 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700861 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400862 gl::Error error = image->copyToStorage2D(mTexStorage, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400863 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
Jamie Madillfeda4d22014-09-17 13:03:29 -0400980 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400981 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
982 index);
983 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700984 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400985 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700986 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400987
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400988 gl::Box region(xoffset, yoffset, 0, width, height, 1);
989 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -0700990}
991
Geoff Langb5348332014-09-02 13:16:34 -0400992gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
993 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
994 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700995{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700996 ASSERT(depth == 1 && zoffset == 0);
997
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400998 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700999
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001000 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -04001001 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001002 {
Geoff Langb5348332014-09-02 13:16:34 -04001003 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001004 }
Geoff Langb5348332014-09-02 13:16:34 -04001005
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001006 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1007 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001008}
1009
1010void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1011{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001012 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001013 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1014
Brandon Jones0511e802014-07-14 16:27:26 -07001015 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1016
1017 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1018 {
1019 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1020 mDirtyImages = true;
1021 }
1022 else
1023 {
1024 ensureRenderTarget();
1025 mImageArray[faceIndex][level]->markClean();
1026
1027 ASSERT(width == height);
1028
1029 if (width > 0 && isValidFaceLevel(faceIndex, level))
1030 {
1031 gl::Rectangle sourceRect;
1032 sourceRect.x = x;
1033 sourceRect.width = width;
1034 sourceRect.y = y;
1035 sourceRect.height = height;
1036
Jamie Madill856d9d42014-09-18 15:08:49 -04001037 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001038 }
1039 }
1040}
1041
1042void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1043{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001044 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001045
1046 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1047 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1048 // rely on the "getBaseLevel*" methods reliably otherwise.
1049 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1050
1051 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1052 {
1053 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1054 mDirtyImages = true;
1055 }
1056 else
1057 {
1058 ensureRenderTarget();
1059
1060 if (isValidFaceLevel(faceIndex, level))
1061 {
1062 updateStorageFaceLevel(faceIndex, level);
1063
1064 gl::Rectangle sourceRect;
1065 sourceRect.x = x;
1066 sourceRect.width = width;
1067 sourceRect.y = y;
1068 sourceRect.height = height;
1069
Jamie Madill856d9d42014-09-18 15:08:49 -04001070 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1071 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001072 }
1073 }
1074}
1075
Brandon Jonescef06ff2014-08-05 13:27:48 -07001076void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001077{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001078 ASSERT(width == height);
1079 ASSERT(depth == 1);
1080
Brandon Jones0511e802014-07-14 16:27:26 -07001081 for (int level = 0; level < levels; level++)
1082 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001083 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001084 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1085 {
1086 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1087 }
1088 }
1089
1090 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1091 {
1092 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1093 {
1094 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1095 }
1096 }
1097
1098 mImmutable = true;
1099
Jamie Madillc4833262014-09-18 16:18:26 -04001100 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001101 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1102 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001103}
1104
Brandon Jones0511e802014-07-14 16:27:26 -07001105// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1106bool TextureD3D_Cube::isCubeComplete() const
1107{
1108 int baseWidth = getBaseLevelWidth();
1109 int baseHeight = getBaseLevelHeight();
1110 GLenum baseFormat = getBaseLevelInternalFormat();
1111
1112 if (baseWidth <= 0 || baseWidth != baseHeight)
1113 {
1114 return false;
1115 }
1116
1117 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1118 {
1119 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1120
1121 if (faceBaseImage.getWidth() != baseWidth ||
1122 faceBaseImage.getHeight() != baseHeight ||
1123 faceBaseImage.getInternalFormat() != baseFormat )
1124 {
1125 return false;
1126 }
1127 }
1128
1129 return true;
1130}
1131
Brandon Jones6053a522014-07-25 16:22:09 -07001132void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1133{
1134 UNREACHABLE();
1135}
1136
1137void TextureD3D_Cube::releaseTexImage()
1138{
1139 UNREACHABLE();
1140}
1141
1142
Jamie Madill4aa79e12014-09-29 10:46:14 -04001143void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001144{
1145 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1146 int levelCount = mipLevels();
1147 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1148 {
1149 for (int level = 1; level < levelCount; level++)
1150 {
1151 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1152 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1153 }
1154 }
Brandon Jones0511e802014-07-14 16:27:26 -07001155}
1156
Jamie Madillac7579c2014-09-17 16:59:33 -04001157unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001158{
Jamie Madillc4833262014-09-18 16:18:26 -04001159 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001160}
1161
Jamie Madillac7579c2014-09-17 16:59:33 -04001162RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001163{
Jamie Madillac7579c2014-09-17 16:59:33 -04001164 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001165
1166 // ensure the underlying texture is created
1167 if (!ensureRenderTarget())
1168 {
1169 return NULL;
1170 }
1171
Jamie Madillac7579c2014-09-17 16:59:33 -04001172 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001173 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001174}
1175
Brandon Jones0511e802014-07-14 16:27:26 -07001176void TextureD3D_Cube::initializeStorage(bool renderTarget)
1177{
1178 // Only initialize the first time this texture is used as a render target or shader resource
1179 if (mTexStorage)
1180 {
1181 return;
1182 }
1183
1184 // do not attempt to create storage for nonexistant data
1185 if (!isFaceLevelComplete(0, 0))
1186 {
1187 return;
1188 }
1189
1190 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1191
1192 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1193 ASSERT(mTexStorage);
1194
1195 // flush image data to the storage
1196 updateStorage();
1197}
1198
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001199TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001200{
1201 GLsizei size = getBaseLevelWidth();
1202
1203 ASSERT(size > 0);
1204
1205 // use existing storage level count, when previously specified by TexStorage*D
1206 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1207
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001208 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001209}
1210
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001211void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001212{
1213 SafeDelete(mTexStorage);
1214 mTexStorage = newCompleteTexStorage;
1215
1216 if (mTexStorage && mTexStorage->isManaged())
1217 {
1218 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1219 {
1220 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1221 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001222 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001223 }
1224 }
1225 }
1226
1227 mDirtyImages = true;
1228}
1229
1230void TextureD3D_Cube::updateStorage()
1231{
1232 ASSERT(mTexStorage != NULL);
1233 GLint storageLevels = mTexStorage->getLevelCount();
1234 for (int face = 0; face < 6; face++)
1235 {
1236 for (int level = 0; level < storageLevels; level++)
1237 {
1238 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1239 {
1240 updateStorageFaceLevel(face, level);
1241 }
1242 }
1243 }
1244}
1245
Brandon Jones0511e802014-07-14 16:27:26 -07001246bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1247{
1248 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1249}
1250
Brandon Jones0511e802014-07-14 16:27:26 -07001251bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1252{
1253 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1254
1255 if (isImmutable())
1256 {
1257 return true;
1258 }
1259
1260 int baseSize = getBaseLevelWidth();
1261
1262 if (baseSize <= 0)
1263 {
1264 return false;
1265 }
1266
1267 // "isCubeComplete" checks for base level completeness and we must call that
1268 // to determine if any face at level 0 is complete. We omit that check here
1269 // to avoid re-checking cube-completeness for every face at level 0.
1270 if (level == 0)
1271 {
1272 return true;
1273 }
1274
1275 // Check that non-zero levels are consistent with the base level.
1276 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1277
1278 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1279 {
1280 return false;
1281 }
1282
1283 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1284 {
1285 return false;
1286 }
1287
1288 return true;
1289}
1290
1291void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1292{
1293 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1294 ImageD3D *image = mImageArray[faceIndex][level];
1295
1296 if (image->isDirty())
1297 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001298 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1299 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1300 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1301 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001302 }
1303}
1304
1305void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1306{
1307 // If there currently is a corresponding storage texture image, it has these parameters
1308 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1309 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1310 const GLenum storageFormat = getBaseLevelInternalFormat();
1311
1312 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1313
1314 if (mTexStorage)
1315 {
1316 const int storageLevels = mTexStorage->getLevelCount();
1317
1318 if ((level >= storageLevels && storageLevels != 0) ||
1319 width != storageWidth ||
1320 height != storageHeight ||
1321 internalformat != storageFormat) // Discard mismatched storage
1322 {
1323 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1324 {
1325 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1326 {
1327 mImageArray[faceIndex][level]->markDirty();
1328 }
1329 }
1330
1331 SafeDelete(mTexStorage);
1332
1333 mDirtyImages = true;
1334 }
1335 }
1336}
1337
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001338gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001339{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001340 ASSERT(index.hasLayer());
1341
1342 GLint level = index.mipIndex;
1343 int faceIndex = static_cast<int>(index.layerIndex);
1344
Brandon Jones0511e802014-07-14 16:27:26 -07001345 if (isValidFaceLevel(faceIndex, level))
1346 {
1347 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001348 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001349 if (error.isError())
1350 {
1351 return error;
1352 }
1353
1354 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001355 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001356
1357 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001358}
1359
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001360gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1361{
1362 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1363}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001364
Jamie Madillcb83dc12014-09-29 10:46:12 -04001365gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1366{
1367 // The "layer" of the image index corresponds to the cube face
1368 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1369}
1370
Brandon Jones78b1acd2014-07-15 15:33:07 -07001371TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001372 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001373{
1374 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1375 {
1376 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1377 }
1378}
1379
1380TextureD3D_3D::~TextureD3D_3D()
1381{
Austin Kinross69822602014-08-12 15:51:37 -07001382 // Delete the Images before the TextureStorage.
1383 // Images might be relying on the TextureStorage for some of their data.
1384 // 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 -07001385 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1386 {
1387 delete mImageArray[i];
1388 }
Austin Kinross69822602014-08-12 15:51:37 -07001389
1390 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001391}
1392
Brandon Jonescef06ff2014-08-05 13:27:48 -07001393Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001394{
1395 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001396 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001397 return mImageArray[level];
1398}
1399
Jamie Madillfeda4d22014-09-17 13:03:29 -04001400Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1401{
1402 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001403 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001404 ASSERT(index.type == GL_TEXTURE_3D);
1405 return mImageArray[index.mipIndex];
1406}
1407
Brandon Jonescef06ff2014-08-05 13:27:48 -07001408GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001409{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001410 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1411 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001412}
1413
Brandon Jones78b1acd2014-07-15 15:33:07 -07001414GLsizei TextureD3D_3D::getWidth(GLint level) const
1415{
1416 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1417 return mImageArray[level]->getWidth();
1418 else
1419 return 0;
1420}
1421
1422GLsizei TextureD3D_3D::getHeight(GLint level) const
1423{
1424 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1425 return mImageArray[level]->getHeight();
1426 else
1427 return 0;
1428}
1429
1430GLsizei TextureD3D_3D::getDepth(GLint level) const
1431{
1432 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1433 return mImageArray[level]->getDepth();
1434 else
1435 return 0;
1436}
1437
1438GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1439{
1440 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1441 return mImageArray[level]->getInternalFormat();
1442 else
1443 return GL_NONE;
1444}
1445
1446bool TextureD3D_3D::isDepth(GLint level) const
1447{
Geoff Lang5d601382014-07-22 15:14:06 -04001448 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001449}
1450
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001451gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1452 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1453 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001454{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001455 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001456 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1457
Brandon Jones78b1acd2014-07-15 15:33:07 -07001458 redefineImage(level, sizedInternalFormat, width, height, depth);
1459
1460 bool fastUnpacked = false;
1461
1462 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1463 if (isFastUnpackable(unpack, sizedInternalFormat))
1464 {
1465 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001466 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1467 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001468 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1469
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001470 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001472 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1473 if (error.isError())
1474 {
1475 return error;
1476 }
1477
Brandon Jones78b1acd2014-07-15 15:33:07 -07001478 // Ensure we don't overwrite our newly initialized data
1479 mImageArray[level]->markClean();
1480
1481 fastUnpacked = true;
1482 }
1483 }
1484
1485 if (!fastUnpacked)
1486 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001487 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1488 if (error.isError())
1489 {
1490 return error;
1491 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001492 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001493
1494 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495}
1496
Geoff Langb5348332014-09-02 13:16:34 -04001497gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1498 GLsizei width, GLsizei height,GLsizei depth,
1499 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001501 ASSERT(target == GL_TEXTURE_3D);
1502
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1504 redefineImage(level, format, width, height, depth);
1505
Geoff Langb5348332014-09-02 13:16:34 -04001506 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001507}
1508
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001509gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1510 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1511 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001512{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001513 ASSERT(target == GL_TEXTURE_3D);
1514
Brandon Jones78b1acd2014-07-15 15:33:07 -07001515 bool fastUnpacked = false;
1516
Jamie Madillac7579c2014-09-17 16:59:33 -04001517 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001518 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillac7579c2014-09-17 16:59:33 -04001519
Brandon Jones78b1acd2014-07-15 15:33:07 -07001520 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1521 if (isFastUnpackable(unpack, getInternalFormat(level)))
1522 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001523 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001524
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001525 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001526 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001527 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1528 if (error.isError())
1529 {
1530 return error;
1531 }
1532
Brandon Jones78b1acd2014-07-15 15:33:07 -07001533 // Ensure we don't overwrite our newly initialized data
1534 mImageArray[level]->markClean();
1535
1536 fastUnpacked = true;
1537 }
1538 }
1539
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001540 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001541 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001542 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1543 pixels, index);
1544 if (error.isError())
1545 {
1546 return error;
1547 }
1548
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001549 return commitRegion(index, destArea);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001550 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001551
1552 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001553}
1554
Geoff Langb5348332014-09-02 13:16:34 -04001555gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1556 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1557 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001558{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001559 ASSERT(target == GL_TEXTURE_3D);
1560
Geoff Langb5348332014-09-02 13:16:34 -04001561 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1562 format, imageSize, pixels, mImageArray[level]);
1563 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001564 {
Geoff Langb5348332014-09-02 13:16:34 -04001565 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001566 }
Geoff Langb5348332014-09-02 13:16:34 -04001567
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001568 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1569 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1570 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001571}
1572
Brandon Jonescef06ff2014-08-05 13:27:48 -07001573void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1574{
1575 UNIMPLEMENTED();
1576}
1577
Brandon Jones78b1acd2014-07-15 15:33:07 -07001578void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1579{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001580 ASSERT(target == GL_TEXTURE_3D);
1581
Brandon Jones78b1acd2014-07-15 15:33:07 -07001582 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1583 // the current level we're copying to is defined (with appropriate format, width & height)
1584 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1585
1586 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1587 {
1588 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1589 mDirtyImages = true;
1590 }
1591 else
1592 {
1593 ensureRenderTarget();
1594
1595 if (isValidLevel(level))
1596 {
1597 updateStorageLevel(level);
1598
1599 gl::Rectangle sourceRect;
1600 sourceRect.x = x;
1601 sourceRect.width = width;
1602 sourceRect.y = y;
1603 sourceRect.height = height;
1604
Jamie Madill856d9d42014-09-18 15:08:49 -04001605 mRenderer->copyImage3D(source, sourceRect,
1606 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1607 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001608 }
1609 }
1610}
1611
Brandon Jonescef06ff2014-08-05 13:27:48 -07001612void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001613{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001614 ASSERT(target == GL_TEXTURE_3D);
1615
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616 for (int level = 0; level < levels; level++)
1617 {
1618 GLsizei levelWidth = std::max(1, width >> level);
1619 GLsizei levelHeight = std::max(1, height >> level);
1620 GLsizei levelDepth = std::max(1, depth >> level);
1621 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1622 }
1623
1624 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1625 {
1626 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1627 }
1628
1629 mImmutable = true;
1630
Jamie Madillc4833262014-09-18 16:18:26 -04001631 bool renderTarget = IsRenderTargetUsage(mUsage);
1632 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001633 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001634}
1635
Brandon Jones6053a522014-07-25 16:22:09 -07001636void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001637{
Brandon Jones6053a522014-07-25 16:22:09 -07001638 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001639}
1640
Brandon Jones6053a522014-07-25 16:22:09 -07001641void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001642{
Brandon Jones6053a522014-07-25 16:22:09 -07001643 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001644}
1645
Brandon Jones6053a522014-07-25 16:22:09 -07001646
Jamie Madill4aa79e12014-09-29 10:46:14 -04001647void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001648{
1649 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1650 int levelCount = mipLevels();
1651 for (int level = 1; level < levelCount; level++)
1652 {
1653 redefineImage(level, getBaseLevelInternalFormat(),
1654 std::max(getBaseLevelWidth() >> level, 1),
1655 std::max(getBaseLevelHeight() >> level, 1),
1656 std::max(getBaseLevelDepth() >> level, 1));
1657 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001658}
1659
Jamie Madillac7579c2014-09-17 16:59:33 -04001660unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001661{
Jamie Madillc4833262014-09-18 16:18:26 -04001662 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001663}
1664
Jamie Madillac7579c2014-09-17 16:59:33 -04001665RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001666{
1667 // ensure the underlying texture is created
1668 if (!ensureRenderTarget())
1669 {
1670 return NULL;
1671 }
1672
Jamie Madillac7579c2014-09-17 16:59:33 -04001673 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001675 updateStorage();
1676 }
1677 else
1678 {
1679 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001680 }
1681
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001682 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683}
1684
1685void TextureD3D_3D::initializeStorage(bool renderTarget)
1686{
1687 // Only initialize the first time this texture is used as a render target or shader resource
1688 if (mTexStorage)
1689 {
1690 return;
1691 }
1692
1693 // do not attempt to create storage for nonexistant data
1694 if (!isLevelComplete(0))
1695 {
1696 return;
1697 }
1698
1699 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1700
1701 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1702 ASSERT(mTexStorage);
1703
1704 // flush image data to the storage
1705 updateStorage();
1706}
1707
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001708TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001709{
1710 GLsizei width = getBaseLevelWidth();
1711 GLsizei height = getBaseLevelHeight();
1712 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001713 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001714
1715 ASSERT(width > 0 && height > 0 && depth > 0);
1716
1717 // use existing storage level count, when previously specified by TexStorage*D
1718 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1719
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001720 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001721}
1722
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001723void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001724{
1725 SafeDelete(mTexStorage);
1726 mTexStorage = newCompleteTexStorage;
1727 mDirtyImages = true;
1728
1729 // We do not support managed 3D storage, as that is D3D9/ES2-only
1730 ASSERT(!mTexStorage->isManaged());
1731}
1732
1733void TextureD3D_3D::updateStorage()
1734{
1735 ASSERT(mTexStorage != NULL);
1736 GLint storageLevels = mTexStorage->getLevelCount();
1737 for (int level = 0; level < storageLevels; level++)
1738 {
1739 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1740 {
1741 updateStorageLevel(level);
1742 }
1743 }
1744}
1745
Brandon Jones78b1acd2014-07-15 15:33:07 -07001746bool TextureD3D_3D::isValidLevel(int level) const
1747{
1748 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1749}
1750
1751bool TextureD3D_3D::isLevelComplete(int level) const
1752{
1753 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1754
1755 if (isImmutable())
1756 {
1757 return true;
1758 }
1759
1760 GLsizei width = getBaseLevelWidth();
1761 GLsizei height = getBaseLevelHeight();
1762 GLsizei depth = getBaseLevelDepth();
1763
1764 if (width <= 0 || height <= 0 || depth <= 0)
1765 {
1766 return false;
1767 }
1768
1769 if (level == 0)
1770 {
1771 return true;
1772 }
1773
1774 ImageD3D *levelImage = mImageArray[level];
1775
1776 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1777 {
1778 return false;
1779 }
1780
1781 if (levelImage->getWidth() != std::max(1, width >> level))
1782 {
1783 return false;
1784 }
1785
1786 if (levelImage->getHeight() != std::max(1, height >> level))
1787 {
1788 return false;
1789 }
1790
1791 if (levelImage->getDepth() != std::max(1, depth >> level))
1792 {
1793 return false;
1794 }
1795
1796 return true;
1797}
1798
1799void TextureD3D_3D::updateStorageLevel(int level)
1800{
1801 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1802 ASSERT(isLevelComplete(level));
1803
1804 if (mImageArray[level]->isDirty())
1805 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001806 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1807 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1808 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 }
1810}
1811
1812void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1813{
1814 // If there currently is a corresponding storage texture image, it has these parameters
1815 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1816 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1817 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1818 const GLenum storageFormat = getBaseLevelInternalFormat();
1819
1820 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1821
1822 if (mTexStorage)
1823 {
1824 const int storageLevels = mTexStorage->getLevelCount();
1825
1826 if ((level >= storageLevels && storageLevels != 0) ||
1827 width != storageWidth ||
1828 height != storageHeight ||
1829 depth != storageDepth ||
1830 internalformat != storageFormat) // Discard mismatched storage
1831 {
1832 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1833 {
1834 mImageArray[i]->markDirty();
1835 }
1836
1837 SafeDelete(mTexStorage);
1838 mDirtyImages = true;
1839 }
1840 }
1841}
1842
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001843gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001845 ASSERT(!index.hasLayer());
1846 GLint level = index.mipIndex;
1847
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848 if (isValidLevel(level))
1849 {
1850 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001851 gl::Error error = image->copyToStorage3D(mTexStorage, level, region.x, region.y, region.z, region.width, region.height, region.depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001852 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001853 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001854 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001856
1857 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001858 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001859
1860 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861}
1862
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001863gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1864{
1865 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1866 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1867}
Brandon Jones142ec422014-07-16 10:31:30 -07001868
Jamie Madillcb83dc12014-09-29 10:46:12 -04001869gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1870{
1871 // The "layer" here does not apply to 3D images. We use one Image per mip.
1872 return gl::ImageIndex::Make3D(mip);
1873}
1874
Brandon Jones142ec422014-07-16 10:31:30 -07001875TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001876 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001877{
1878 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1879 {
1880 mLayerCounts[level] = 0;
1881 mImageArray[level] = NULL;
1882 }
1883}
1884
1885TextureD3D_2DArray::~TextureD3D_2DArray()
1886{
Austin Kinross69822602014-08-12 15:51:37 -07001887 // Delete the Images before the TextureStorage.
1888 // Images might be relying on the TextureStorage for some of their data.
1889 // 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 -07001890 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001891 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001892}
1893
Brandon Jones142ec422014-07-16 10:31:30 -07001894Image *TextureD3D_2DArray::getImage(int level, int layer) const
1895{
1896 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1897 ASSERT(layer < mLayerCounts[level]);
1898 return mImageArray[level][layer];
1899}
1900
Jamie Madillfeda4d22014-09-17 13:03:29 -04001901Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1902{
1903 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1904 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1905 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1906 return mImageArray[index.mipIndex][index.layerIndex];
1907}
1908
Brandon Jones142ec422014-07-16 10:31:30 -07001909GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1910{
1911 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1912 return mLayerCounts[level];
1913}
1914
Brandon Jones142ec422014-07-16 10:31:30 -07001915GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1916{
1917 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1918}
1919
1920GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1921{
1922 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1923}
1924
Brandon Jones142ec422014-07-16 10:31:30 -07001925GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1926{
1927 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1928}
1929
1930bool TextureD3D_2DArray::isDepth(GLint level) const
1931{
Geoff Lang5d601382014-07-22 15:14:06 -04001932 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001933}
1934
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001935gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1936 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1937 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001938{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001939 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1940
Geoff Lang5d601382014-07-22 15:14:06 -04001941 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1942
Brandon Jones142ec422014-07-16 10:31:30 -07001943 redefineImage(level, sizedInternalFormat, width, height, depth);
1944
Geoff Lang5d601382014-07-22 15:14:06 -04001945 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1946 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001947
1948 for (int i = 0; i < depth; i++)
1949 {
1950 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001951 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1952 if (error.isError())
1953 {
1954 return error;
1955 }
Brandon Jones142ec422014-07-16 10:31:30 -07001956 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001957
1958 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001959}
1960
Geoff Langb5348332014-09-02 13:16:34 -04001961gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1962 GLsizei width, GLsizei height, GLsizei depth,
1963 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001964{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001965 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1966
Brandon Jones142ec422014-07-16 10:31:30 -07001967 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1968 redefineImage(level, format, width, height, depth);
1969
Geoff Lang5d601382014-07-22 15:14:06 -04001970 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1971 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001972
1973 for (int i = 0; i < depth; i++)
1974 {
1975 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001976 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1977 if (error.isError())
1978 {
1979 return error;
1980 }
Brandon Jones142ec422014-07-16 10:31:30 -07001981 }
Geoff Langb5348332014-09-02 13:16:34 -04001982
1983 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001984}
1985
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001986gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1987 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1988 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001989{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001990 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1991
Geoff Lang5d601382014-07-22 15:14:06 -04001992 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1993 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001994
1995 for (int i = 0; i < depth; i++)
1996 {
1997 int layer = zoffset + i;
1998 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1999
Jamie Madillfeda4d22014-09-17 13:03:29 -04002000 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002001 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2002 layerPixels, index);
2003 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002004 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002005 return error;
2006 }
2007
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002008 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2009 error = commitRegion(index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002010 if (error.isError())
2011 {
2012 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002013 }
2014 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002015
2016 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002017}
2018
Geoff Langb5348332014-09-02 13:16:34 -04002019gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2020 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2021 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002022{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002023 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2024
Geoff Lang5d601382014-07-22 15:14:06 -04002025 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2026 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002027
2028 for (int i = 0; i < depth; i++)
2029 {
2030 int layer = zoffset + i;
2031 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2032
Geoff Langb5348332014-09-02 13:16:34 -04002033 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2034 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002035 {
Geoff Langb5348332014-09-02 13:16:34 -04002036 return error;
2037 }
2038
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002039 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2040 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2041 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002042 if (error.isError())
2043 {
2044 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002045 }
2046 }
Geoff Langb5348332014-09-02 13:16:34 -04002047
2048 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002049}
2050
Brandon Jonescef06ff2014-08-05 13:27:48 -07002051void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2052{
2053 UNIMPLEMENTED();
2054}
2055
Brandon Jones142ec422014-07-16 10:31:30 -07002056void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2057{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002058 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2059
Brandon Jones142ec422014-07-16 10:31:30 -07002060 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2061 // the current level we're copying to is defined (with appropriate format, width & height)
2062 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2063
2064 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2065 {
2066 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2067 mDirtyImages = true;
2068 }
2069 else
2070 {
2071 ensureRenderTarget();
2072
2073 if (isValidLevel(level))
2074 {
2075 updateStorageLevel(level);
2076
2077 gl::Rectangle sourceRect;
2078 sourceRect.x = x;
2079 sourceRect.width = width;
2080 sourceRect.y = y;
2081 sourceRect.height = height;
2082
Jamie Madill856d9d42014-09-18 15:08:49 -04002083 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2084 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002085 }
2086 }
2087}
2088
Brandon Jonescef06ff2014-08-05 13:27:48 -07002089void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002090{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002091 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2092
Brandon Jones142ec422014-07-16 10:31:30 -07002093 deleteImages();
2094
2095 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2096 {
2097 GLsizei levelWidth = std::max(1, width >> level);
2098 GLsizei levelHeight = std::max(1, height >> level);
2099
2100 mLayerCounts[level] = (level < levels ? depth : 0);
2101
2102 if (mLayerCounts[level] > 0)
2103 {
2104 // Create new images for this level
2105 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2106
2107 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2108 {
2109 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2110 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2111 levelHeight, 1, true);
2112 }
2113 }
2114 }
2115
2116 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002117
2118 bool renderTarget = IsRenderTargetUsage(mUsage);
2119 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002120 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002121}
2122
Brandon Jones6053a522014-07-25 16:22:09 -07002123void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002124{
Brandon Jones6053a522014-07-25 16:22:09 -07002125 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002126}
2127
Brandon Jones6053a522014-07-25 16:22:09 -07002128void TextureD3D_2DArray::releaseTexImage()
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 -07002133
Jamie Madill4aa79e12014-09-29 10:46:14 -04002134void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002135{
2136 int baseWidth = getBaseLevelWidth();
2137 int baseHeight = getBaseLevelHeight();
2138 int baseDepth = getBaseLevelDepth();
2139 GLenum baseFormat = getBaseLevelInternalFormat();
2140
2141 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2142 int levelCount = mipLevels();
2143 for (int level = 1; level < levelCount; level++)
2144 {
2145 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2146 }
Brandon Jones142ec422014-07-16 10:31:30 -07002147}
2148
Jamie Madillac7579c2014-09-17 16:59:33 -04002149unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002150{
Jamie Madillc4833262014-09-18 16:18:26 -04002151 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002152}
2153
Jamie Madillac7579c2014-09-17 16:59:33 -04002154RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002155{
2156 // ensure the underlying texture is created
2157 if (!ensureRenderTarget())
2158 {
2159 return NULL;
2160 }
2161
Jamie Madillac7579c2014-09-17 16:59:33 -04002162 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002163 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002164}
2165
2166void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2167{
2168 // Only initialize the first time this texture is used as a render target or shader resource
2169 if (mTexStorage)
2170 {
2171 return;
2172 }
2173
2174 // do not attempt to create storage for nonexistant data
2175 if (!isLevelComplete(0))
2176 {
2177 return;
2178 }
2179
2180 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2181
2182 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2183 ASSERT(mTexStorage);
2184
2185 // flush image data to the storage
2186 updateStorage();
2187}
2188
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002189TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002190{
2191 GLsizei width = getBaseLevelWidth();
2192 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002193 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002194 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002195
2196 ASSERT(width > 0 && height > 0 && depth > 0);
2197
2198 // use existing storage level count, when previously specified by TexStorage*D
2199 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2200
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002201 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002202}
2203
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002204void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002205{
2206 SafeDelete(mTexStorage);
2207 mTexStorage = newCompleteTexStorage;
2208 mDirtyImages = true;
2209
2210 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2211 ASSERT(!mTexStorage->isManaged());
2212}
2213
2214void TextureD3D_2DArray::updateStorage()
2215{
2216 ASSERT(mTexStorage != NULL);
2217 GLint storageLevels = mTexStorage->getLevelCount();
2218 for (int level = 0; level < storageLevels; level++)
2219 {
2220 if (isLevelComplete(level))
2221 {
2222 updateStorageLevel(level);
2223 }
2224 }
2225}
2226
Brandon Jones142ec422014-07-16 10:31:30 -07002227bool TextureD3D_2DArray::isValidLevel(int level) const
2228{
2229 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2230}
2231
2232bool TextureD3D_2DArray::isLevelComplete(int level) const
2233{
2234 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2235
2236 if (isImmutable())
2237 {
2238 return true;
2239 }
2240
2241 GLsizei width = getBaseLevelWidth();
2242 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002243 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002244
2245 if (width <= 0 || height <= 0 || layers <= 0)
2246 {
2247 return false;
2248 }
2249
2250 if (level == 0)
2251 {
2252 return true;
2253 }
2254
2255 if (getInternalFormat(level) != getInternalFormat(0))
2256 {
2257 return false;
2258 }
2259
2260 if (getWidth(level) != std::max(1, width >> level))
2261 {
2262 return false;
2263 }
2264
2265 if (getHeight(level) != std::max(1, height >> level))
2266 {
2267 return false;
2268 }
2269
Jamie Madill3269bcb2014-09-30 16:33:52 -04002270 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002271 {
2272 return false;
2273 }
2274
2275 return true;
2276}
2277
2278void TextureD3D_2DArray::updateStorageLevel(int level)
2279{
2280 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2281 ASSERT(isLevelComplete(level));
2282
2283 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2284 {
2285 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2286 if (mImageArray[level][layer]->isDirty())
2287 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002288 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2289 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2290 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002291 }
2292 }
2293}
2294
2295void TextureD3D_2DArray::deleteImages()
2296{
2297 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2298 {
2299 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2300 {
2301 delete mImageArray[level][layer];
2302 }
2303 delete[] mImageArray[level];
2304 mImageArray[level] = NULL;
2305 mLayerCounts[level] = 0;
2306 }
2307}
2308
2309void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2310{
2311 // If there currently is a corresponding storage texture image, it has these parameters
2312 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2313 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002314 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002315 const GLenum storageFormat = getBaseLevelInternalFormat();
2316
2317 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2318 {
2319 delete mImageArray[level][layer];
2320 }
2321 delete[] mImageArray[level];
2322 mImageArray[level] = NULL;
2323 mLayerCounts[level] = depth;
2324
2325 if (depth > 0)
2326 {
2327 mImageArray[level] = new ImageD3D*[depth]();
2328
2329 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2330 {
2331 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2332 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2333 }
2334 }
2335
2336 if (mTexStorage)
2337 {
2338 const int storageLevels = mTexStorage->getLevelCount();
2339
2340 if ((level >= storageLevels && storageLevels != 0) ||
2341 width != storageWidth ||
2342 height != storageHeight ||
2343 depth != storageDepth ||
2344 internalformat != storageFormat) // Discard mismatched storage
2345 {
2346 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2347 {
2348 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2349 {
2350 mImageArray[level][layer]->markDirty();
2351 }
2352 }
2353
2354 delete mTexStorage;
2355 mTexStorage = NULL;
2356 mDirtyImages = true;
2357 }
2358 }
2359}
2360
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002361gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002362{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002363 ASSERT(index.hasLayer());
2364 GLint level = index.mipIndex;
2365 GLint layerTarget = index.layerIndex;
2366
Jamie Madill3269bcb2014-09-30 16:33:52 -04002367 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002368 {
2369 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002370 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, region.x, region.y, layerTarget, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002371 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002372 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002373 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002374 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002375
2376 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002377 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002378
2379 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002380}
2381
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002382gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2383{
2384 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2385}
2386
Jamie Madillcb83dc12014-09-29 10:46:12 -04002387gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2388{
2389 return gl::ImageIndex::Make2DArray(mip, layer);
2390}
2391
Brandon Jones78b1acd2014-07-15 15:33:07 -07002392}