blob: 19f73208ccf45f227f7408f862759c6677cb6826 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001#include "precompiled.h"
2//
3// Copyright 2014 The ANGLE Project Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
9
10#include "common/mathutil.h"
Brandon Jones0511e802014-07-14 16:27:26 -070011#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libEGL/Surface.h"
13#include "libGLESv2/Buffer.h"
14#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070015#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070016#include "libGLESv2/main.h"
17#include "libGLESv2/formatutils.h"
18#include "libGLESv2/renderer/BufferImpl.h"
19#include "libGLESv2/renderer/RenderTarget.h"
20#include "libGLESv2/renderer/Renderer.h"
21#include "libGLESv2/renderer/d3d/ImageD3D.h"
22#include "libGLESv2/renderer/d3d/TextureD3D.h"
23#include "libGLESv2/renderer/d3d/TextureStorage.h"
24
25namespace rx
26{
27
Brandon Jonesf47bebc2014-07-09 14:28:42 -070028bool IsRenderTargetUsage(GLenum usage)
29{
30 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
31}
32
Brandon Jones78b1acd2014-07-15 15:33:07 -070033TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070034 : mRenderer(renderer),
35 mUsage(GL_NONE),
36 mDirtyImages(true),
37 mImmutable(false)
38{
39}
40
41TextureD3D::~TextureD3D()
42{
43}
44
Brandon Jones6053a522014-07-25 16:22:09 -070045TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
46{
47 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
48 return static_cast<TextureD3D*>(texture);
49}
50
51TextureStorageInterface *TextureD3D::getNativeTexture()
52{
53 // ensure the underlying texture is created
54 initializeStorage(false);
55
56 TextureStorageInterface *storage = getBaseLevelStorage();
57 if (storage)
58 {
59 updateStorage();
60 }
61
62 return storage;
63}
64
Brandon Jonesf47bebc2014-07-09 14:28:42 -070065GLint TextureD3D::getBaseLevelWidth() const
66{
Brandon Jones78b1acd2014-07-15 15:33:07 -070067 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070068 return (baseImage ? baseImage->getWidth() : 0);
69}
70
71GLint TextureD3D::getBaseLevelHeight() const
72{
Brandon Jones78b1acd2014-07-15 15:33:07 -070073 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070074 return (baseImage ? baseImage->getHeight() : 0);
75}
76
77GLint TextureD3D::getBaseLevelDepth() const
78{
Brandon Jones78b1acd2014-07-15 15:33:07 -070079 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070080 return (baseImage ? baseImage->getDepth() : 0);
81}
82
83// Note: "base level image" is loosely defined to be any image from the base level,
84// where in the base of 2D array textures and cube maps there are several. Don't use
85// the base level image for anything except querying texture format and size.
86GLenum TextureD3D::getBaseLevelInternalFormat() const
87{
Brandon Jones78b1acd2014-07-15 15:33:07 -070088 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070089 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
90}
91
Brandon Jones78b1acd2014-07-15 15:33:07 -070092void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070093{
94 // No-op
95 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
96 {
97 return;
98 }
99
100 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
101 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
102 const void *pixelData = pixels;
103
104 if (unpack.pixelBuffer.id() != 0)
105 {
106 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
107 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
108 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
109 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
110 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
111 const void *bufferData = pixelBuffer->getImplementation()->getData();
112 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
113 }
114
115 if (pixelData != NULL)
116 {
117 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
118 mDirtyImages = true;
119 }
120}
121
122bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700123 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124{
125 const void *pixelData = pixels;
126
127 // CPU readback & copy where direct GPU copy is not supported
128 if (unpack.pixelBuffer.id() != 0)
129 {
130 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
131 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
132 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
133 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
134 const void *bufferData = pixelBuffer->getImplementation()->getData();
135 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
136 }
137
138 if (pixelData != NULL)
139 {
140 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
141 mDirtyImages = true;
142 }
143
144 return true;
145}
146
Brandon Jones78b1acd2014-07-15 15:33:07 -0700147void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
149 if (pixels != NULL)
150 {
151 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
152 mDirtyImages = true;
153 }
154}
155
156bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700157 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158{
159 if (pixels != NULL)
160 {
161 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
162 mDirtyImages = true;
163 }
164
165 return true;
166}
167
168bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
169{
170 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
171}
172
173bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700174 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700175{
176 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
177 {
178 return true;
179 }
180
181 // In order to perform the fast copy through the shader, we must have the right format, and be able
182 // to create a render target.
183 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
184
185 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
186
187 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
188}
189
190GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
191{
192 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
193 {
194 // Maximum number of levels
195 return gl::log2(std::max(std::max(width, height), depth)) + 1;
196 }
197 else
198 {
199 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
200 return 1;
201 }
202}
203
204int TextureD3D::mipLevels() const
205{
206 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
207}
208
209
Brandon Jones78b1acd2014-07-15 15:33:07 -0700210TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211 : TextureD3D(renderer),
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700212 mTexStorage(NULL)
213{
214 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
215 {
216 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
217 }
218}
219
220TextureD3D_2D::~TextureD3D_2D()
221{
222 SafeDelete(mTexStorage);
223
224 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
225 {
226 delete mImageArray[i];
227 }
228}
229
Brandon Jonescef06ff2014-08-05 13:27:48 -0700230Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231{
232 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700233 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700234 return mImageArray[level];
235}
236
Brandon Jonescef06ff2014-08-05 13:27:48 -0700237GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700239 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
240 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700241}
242
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700243GLsizei TextureD3D_2D::getWidth(GLint level) const
244{
245 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
246 return mImageArray[level]->getWidth();
247 else
248 return 0;
249}
250
251GLsizei TextureD3D_2D::getHeight(GLint level) const
252{
253 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
254 return mImageArray[level]->getHeight();
255 else
256 return 0;
257}
258
259GLenum TextureD3D_2D::getInternalFormat(GLint level) const
260{
261 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
262 return mImageArray[level]->getInternalFormat();
263 else
264 return GL_NONE;
265}
266
267GLenum TextureD3D_2D::getActualFormat(GLint level) const
268{
269 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
270 return mImageArray[level]->getActualFormat();
271 else
272 return GL_NONE;
273}
274
275bool TextureD3D_2D::isDepth(GLint level) const
276{
Geoff Lang5d601382014-07-22 15:14:06 -0400277 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700278}
279
Brandon Jonescef06ff2014-08-05 13:27:48 -0700280void TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700281{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700282 ASSERT(target == GL_TEXTURE_2D && depth == 1);
283
Geoff Lang5d601382014-07-22 15:14:06 -0400284 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
285
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700286 bool fastUnpacked = false;
287
Brandon Jonescef06ff2014-08-05 13:27:48 -0700288 redefineImage(level, sizedInternalFormat, width, height);
289
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700290 // Attempt a fast gpu copy of the pixel data to the surface
291 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
292 {
293 // Will try to create RT storage if it does not exist
Brandon Jonescef06ff2014-08-05 13:27:48 -0700294 RenderTarget *destRenderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700295 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
296
297 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
298 {
299 // Ensure we don't overwrite our newly initialized data
300 mImageArray[level]->markClean();
301
302 fastUnpacked = true;
303 }
304 }
305
306 if (!fastUnpacked)
307 {
308 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
309 }
310}
311
Brandon Jonescef06ff2014-08-05 13:27:48 -0700312void TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700313{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700314 ASSERT(target == GL_TEXTURE_2D && depth == 1);
315
316 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
317 redefineImage(level, format, width, height);
318
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700319 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
320}
321
Brandon Jonescef06ff2014-08-05 13:27:48 -0700322void TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700323{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700324 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
325
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700326 bool fastUnpacked = false;
327
328 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
329 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700330 RenderTarget *renderTarget = getRenderTarget(level, 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700331 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
332
333 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
334 {
335 // Ensure we don't overwrite our newly initialized data
336 mImageArray[level]->markClean();
337
338 fastUnpacked = true;
339 }
340 }
341
342 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
343 {
344 commitRect(level, xoffset, yoffset, width, height);
345 }
346}
347
Brandon Jonescef06ff2014-08-05 13:27:48 -0700348void TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700349{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700350 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
351
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700352 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
353 {
354 commitRect(level, xoffset, yoffset, width, height);
355 }
356}
357
Brandon Jonescef06ff2014-08-05 13:27:48 -0700358void 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 -0700359{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700360 ASSERT(target == GL_TEXTURE_2D);
361
362 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
363 redefineImage(level, sizedInternalFormat, width, height);
364
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700365 if (!mImageArray[level]->isRenderableFormat())
366 {
367 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
368 mDirtyImages = true;
369 }
370 else
371 {
372 ensureRenderTarget();
373 mImageArray[level]->markClean();
374
375 if (width != 0 && height != 0 && isValidLevel(level))
376 {
377 gl::Rectangle sourceRect;
378 sourceRect.x = x;
379 sourceRect.width = width;
380 sourceRect.y = y;
381 sourceRect.height = height;
382
383 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
384 }
385 }
386}
387
388void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
389{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700390 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
391
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700392 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
393 // the current level we're copying to is defined (with appropriate format, width & height)
394 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
395
396 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
397 {
398 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
399 mDirtyImages = true;
400 }
401 else
402 {
403 ensureRenderTarget();
404
405 if (isValidLevel(level))
406 {
407 updateStorageLevel(level);
408
409 gl::Rectangle sourceRect;
410 sourceRect.x = x;
411 sourceRect.width = width;
412 sourceRect.y = y;
413 sourceRect.height = height;
414
415 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400416 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700417 xoffset, yoffset, mTexStorage, level);
418 }
419 }
420}
421
Brandon Jonescef06ff2014-08-05 13:27:48 -0700422void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700423{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700424 ASSERT(target == GL_TEXTURE_2D && depth == 1);
425
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700426 for (int level = 0; level < levels; level++)
427 {
428 GLsizei levelWidth = std::max(1, width >> level);
429 GLsizei levelHeight = std::max(1, height >> level);
430 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
431 }
432
433 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
434 {
435 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
436 }
437
438 mImmutable = true;
439
Brandon Jones78b1acd2014-07-15 15:33:07 -0700440 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700441}
442
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700443void TextureD3D_2D::bindTexImage(egl::Surface *surface)
444{
445 GLenum internalformat = surface->getFormat();
446
447 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
448
449 if (mTexStorage)
450 {
451 SafeDelete(mTexStorage);
452 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700453 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700454
455 mDirtyImages = true;
456}
457
458void TextureD3D_2D::releaseTexImage()
459{
460 if (mTexStorage)
461 {
462 SafeDelete(mTexStorage);
463 }
464
465 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
466 {
467 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
468 }
469}
470
471void TextureD3D_2D::generateMipmaps()
472{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700473 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700474 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700475 for (int level = 1; level < levelCount; level++)
476 {
477 redefineImage(level, getBaseLevelInternalFormat(),
478 std::max(getBaseLevelWidth() >> level, 1),
479 std::max(getBaseLevelHeight() >> level, 1));
480 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481
482 if (mTexStorage && mTexStorage->isRenderTarget())
483 {
484 for (int level = 1; level < levelCount; level++)
485 {
486 mTexStorage->generateMipmap(level);
487
488 mImageArray[level]->markClean();
489 }
490 }
491 else
492 {
493 for (int level = 1; level < levelCount; level++)
494 {
495 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
496 }
497 }
498}
499
Brandon Jonescef06ff2014-08-05 13:27:48 -0700500unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700501{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700502 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
504}
505
Brandon Jonescef06ff2014-08-05 13:27:48 -0700506RenderTarget *TextureD3D_2D::getRenderTarget(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700507{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700508 ASSERT(layer == 0);
509
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700510 // ensure the underlying texture is created
511 if (!ensureRenderTarget())
512 {
513 return NULL;
514 }
515
516 updateStorageLevel(level);
517
518 // ensure this is NOT a depth texture
519 if (isDepth(level))
520 {
521 return NULL;
522 }
523
524 return mTexStorage->getRenderTarget(level);
525}
526
Brandon Jonescef06ff2014-08-05 13:27:48 -0700527RenderTarget *TextureD3D_2D::getDepthStencil(GLint level, GLint layer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700528{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700529 ASSERT(layer == 0);
530
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531 // ensure the underlying texture is created
532 if (!ensureRenderTarget())
533 {
534 return NULL;
535 }
536
537 updateStorageLevel(level);
538
539 // ensure this is actually a depth texture
540 if (!isDepth(level))
541 {
542 return NULL;
543 }
544
545 return mTexStorage->getRenderTarget(level);
546}
547
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700548bool TextureD3D_2D::isValidLevel(int level) const
549{
550 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
551}
552
553bool TextureD3D_2D::isLevelComplete(int level) const
554{
555 if (isImmutable())
556 {
557 return true;
558 }
559
Brandon Jones78b1acd2014-07-15 15:33:07 -0700560 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700561
562 GLsizei width = baseImage->getWidth();
563 GLsizei height = baseImage->getHeight();
564
565 if (width <= 0 || height <= 0)
566 {
567 return false;
568 }
569
570 // The base image level is complete if the width and height are positive
571 if (level == 0)
572 {
573 return true;
574 }
575
576 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700577 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700578
579 if (image->getInternalFormat() != baseImage->getInternalFormat())
580 {
581 return false;
582 }
583
584 if (image->getWidth() != std::max(1, width >> level))
585 {
586 return false;
587 }
588
589 if (image->getHeight() != std::max(1, height >> level))
590 {
591 return false;
592 }
593
594 return true;
595}
596
597// Constructs a native texture resource from the texture images
598void TextureD3D_2D::initializeStorage(bool renderTarget)
599{
600 // Only initialize the first time this texture is used as a render target or shader resource
601 if (mTexStorage)
602 {
603 return;
604 }
605
606 // do not attempt to create storage for nonexistant data
607 if (!isLevelComplete(0))
608 {
609 return;
610 }
611
612 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
613
614 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
615 ASSERT(mTexStorage);
616
617 // flush image data to the storage
618 updateStorage();
619}
620
Brandon Jones78b1acd2014-07-15 15:33:07 -0700621TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622{
623 GLsizei width = getBaseLevelWidth();
624 GLsizei height = getBaseLevelHeight();
625
626 ASSERT(width > 0 && height > 0);
627
628 // use existing storage level count, when previously specified by TexStorage*D
629 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
630
Brandon Jones78b1acd2014-07-15 15:33:07 -0700631 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632}
633
634void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
635{
636 SafeDelete(mTexStorage);
637 mTexStorage = newCompleteTexStorage;
638
639 if (mTexStorage && mTexStorage->isManaged())
640 {
641 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
642 {
643 mImageArray[level]->setManagedSurface(mTexStorage, level);
644 }
645 }
646
647 mDirtyImages = true;
648}
649
650void TextureD3D_2D::updateStorage()
651{
652 ASSERT(mTexStorage != NULL);
653 GLint storageLevels = mTexStorage->getLevelCount();
654 for (int level = 0; level < storageLevels; level++)
655 {
656 if (mImageArray[level]->isDirty() && isLevelComplete(level))
657 {
658 updateStorageLevel(level);
659 }
660 }
661}
662
663bool TextureD3D_2D::ensureRenderTarget()
664{
665 initializeStorage(true);
666
667 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
668 {
669 ASSERT(mTexStorage);
670 if (!mTexStorage->isRenderTarget())
671 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700672 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700673
674 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
675 {
676 delete newRenderTargetStorage;
677 return gl::error(GL_OUT_OF_MEMORY, false);
678 }
679
680 setCompleteTexStorage(newRenderTargetStorage);
681 }
682 }
683
684 return (mTexStorage && mTexStorage->isRenderTarget());
685}
686
687TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
688{
689 return mTexStorage;
690}
691
692const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
693{
694 return mImageArray[0];
695}
696
697void TextureD3D_2D::updateStorageLevel(int level)
698{
699 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
700 ASSERT(isLevelComplete(level));
701
702 if (mImageArray[level]->isDirty())
703 {
704 commitRect(level, 0, 0, getWidth(level), getHeight(level));
705 }
706}
707
708void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
709{
710 // If there currently is a corresponding storage texture image, it has these parameters
711 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
712 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
713 const GLenum storageFormat = getBaseLevelInternalFormat();
714
715 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
716
717 if (mTexStorage)
718 {
719 const int storageLevels = mTexStorage->getLevelCount();
720
721 if ((level >= storageLevels && storageLevels != 0) ||
722 width != storageWidth ||
723 height != storageHeight ||
724 internalformat != storageFormat) // Discard mismatched storage
725 {
726 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
727 {
728 mImageArray[i]->markDirty();
729 }
730
731 SafeDelete(mTexStorage);
732 mDirtyImages = true;
733 }
734 }
735}
736
737void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
738{
739 if (isValidLevel(level))
740 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700741 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
743 {
744 image->markClean();
745 }
746 }
747}
748
Brandon Jones0511e802014-07-14 16:27:26 -0700749
Brandon Jones78b1acd2014-07-15 15:33:07 -0700750TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -0700751 : TextureD3D(renderer),
Brandon Jones0511e802014-07-14 16:27:26 -0700752 mTexStorage(NULL)
753{
754 for (int i = 0; i < 6; i++)
755 {
756 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
757 {
758 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
759 }
760 }
761}
762
763TextureD3D_Cube::~TextureD3D_Cube()
764{
765 SafeDelete(mTexStorage);
766
767 for (int i = 0; i < 6; i++)
768 {
769 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
770 {
771 SafeDelete(mImageArray[i][j]);
772 }
773 }
774}
775
Brandon Jonescef06ff2014-08-05 13:27:48 -0700776Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700777{
778 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700779 ASSERT(layer < 6);
780 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700781}
782
Brandon Jonescef06ff2014-08-05 13:27:48 -0700783GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700784{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700785 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
786 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700787}
788
Brandon Jonescef06ff2014-08-05 13:27:48 -0700789GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700790{
791 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700792 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700793 else
794 return GL_NONE;
795}
796
Brandon Jonescef06ff2014-08-05 13:27:48 -0700797bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700798{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700799 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700800}
801
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802void TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700803{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700804 ASSERT(depth == 1);
805
806 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400807 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700808
809 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
810
811 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
812}
813
Brandon Jonescef06ff2014-08-05 13:27:48 -0700814void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700815{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700816 ASSERT(depth == 1);
817
Brandon Jones0511e802014-07-14 16:27:26 -0700818 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700819 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
820
Brandon Jones0511e802014-07-14 16:27:26 -0700821 redefineImage(faceIndex, level, format, width, height);
822
823 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
824}
825
Brandon Jonescef06ff2014-08-05 13:27:48 -0700826void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700827{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700828 ASSERT(depth == 1 && zoffset == 0);
829
830 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
831
Brandon Jones0511e802014-07-14 16:27:26 -0700832 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
833 {
834 commitRect(faceIndex, level, xoffset, yoffset, width, height);
835 }
836}
837
Brandon Jonescef06ff2014-08-05 13:27:48 -0700838void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700839{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700840 ASSERT(depth == 1 && zoffset == 0);
841
842 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
843
Brandon Jones0511e802014-07-14 16:27:26 -0700844 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
845 {
846 commitRect(faceIndex, level, xoffset, yoffset, width, height);
847 }
848}
849
850void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
851{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700852 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400853 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
854
Brandon Jones0511e802014-07-14 16:27:26 -0700855 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
856
857 if (!mImageArray[faceIndex][level]->isRenderableFormat())
858 {
859 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
860 mDirtyImages = true;
861 }
862 else
863 {
864 ensureRenderTarget();
865 mImageArray[faceIndex][level]->markClean();
866
867 ASSERT(width == height);
868
869 if (width > 0 && isValidFaceLevel(faceIndex, level))
870 {
871 gl::Rectangle sourceRect;
872 sourceRect.x = x;
873 sourceRect.width = width;
874 sourceRect.y = y;
875 sourceRect.height = height;
876
877 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
878 }
879 }
880}
881
882void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
883{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700884 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700885
886 // We can only make our texture storage to a render target if the level we're copying *to* is complete
887 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
888 // rely on the "getBaseLevel*" methods reliably otherwise.
889 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
890
891 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
892 {
893 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
894 mDirtyImages = true;
895 }
896 else
897 {
898 ensureRenderTarget();
899
900 if (isValidFaceLevel(faceIndex, level))
901 {
902 updateStorageFaceLevel(faceIndex, level);
903
904 gl::Rectangle sourceRect;
905 sourceRect.x = x;
906 sourceRect.width = width;
907 sourceRect.y = y;
908 sourceRect.height = height;
909
Geoff Lang5d601382014-07-22 15:14:06 -0400910 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700911 xoffset, yoffset, mTexStorage, target, level);
912 }
913 }
914}
915
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -0700917{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700918 ASSERT(width == height);
919 ASSERT(depth == 1);
920
Brandon Jones0511e802014-07-14 16:27:26 -0700921 for (int level = 0; level < levels; level++)
922 {
Brandon Jonescef06ff2014-08-05 13:27:48 -0700923 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -0700924 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
925 {
926 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
927 }
928 }
929
930 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
931 {
932 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
933 {
934 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
935 }
936 }
937
938 mImmutable = true;
939
Brandon Jonescef06ff2014-08-05 13:27:48 -0700940 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, levels));
Brandon Jones0511e802014-07-14 16:27:26 -0700941}
942
Brandon Jones0511e802014-07-14 16:27:26 -0700943// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
944bool TextureD3D_Cube::isCubeComplete() const
945{
946 int baseWidth = getBaseLevelWidth();
947 int baseHeight = getBaseLevelHeight();
948 GLenum baseFormat = getBaseLevelInternalFormat();
949
950 if (baseWidth <= 0 || baseWidth != baseHeight)
951 {
952 return false;
953 }
954
955 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
956 {
957 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
958
959 if (faceBaseImage.getWidth() != baseWidth ||
960 faceBaseImage.getHeight() != baseHeight ||
961 faceBaseImage.getInternalFormat() != baseFormat )
962 {
963 return false;
964 }
965 }
966
967 return true;
968}
969
Brandon Jones6053a522014-07-25 16:22:09 -0700970void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
971{
972 UNREACHABLE();
973}
974
975void TextureD3D_Cube::releaseTexImage()
976{
977 UNREACHABLE();
978}
979
980
Brandon Jones0511e802014-07-14 16:27:26 -0700981void TextureD3D_Cube::generateMipmaps()
982{
983 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
984 int levelCount = mipLevels();
985 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
986 {
987 for (int level = 1; level < levelCount; level++)
988 {
989 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
990 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
991 }
992 }
993
994 if (mTexStorage && mTexStorage->isRenderTarget())
995 {
996 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
997 {
998 for (int level = 1; level < levelCount; level++)
999 {
1000 mTexStorage->generateMipmap(faceIndex, level);
1001
1002 mImageArray[faceIndex][level]->markClean();
1003 }
1004 }
1005 }
1006 else
1007 {
1008 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1009 {
1010 for (int level = 1; level < levelCount; level++)
1011 {
1012 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1013 }
1014 }
1015 }
1016}
1017
Brandon Jonescef06ff2014-08-05 13:27:48 -07001018unsigned int TextureD3D_Cube::getRenderTargetSerial(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001019{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001020 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001021 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1022}
1023
Brandon Jonescef06ff2014-08-05 13:27:48 -07001024RenderTarget *TextureD3D_Cube::getRenderTarget(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001025{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001026 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001027 ASSERT(gl::IsCubemapTextureTarget(target));
1028
1029 // ensure the underlying texture is created
1030 if (!ensureRenderTarget())
1031 {
1032 return NULL;
1033 }
1034
Brandon Jonescef06ff2014-08-05 13:27:48 -07001035 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001036
1037 // ensure this is NOT a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001038 if (isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001039 {
1040 return NULL;
1041 }
1042
1043 return mTexStorage->getRenderTarget(target, level);
1044}
1045
Brandon Jonescef06ff2014-08-05 13:27:48 -07001046RenderTarget *TextureD3D_Cube::getDepthStencil(GLint level, GLint layer)
Brandon Jones0511e802014-07-14 16:27:26 -07001047{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001048 GLenum target = gl::TextureCubeMap::layerIndexToTarget(layer);
Brandon Jones0511e802014-07-14 16:27:26 -07001049 ASSERT(gl::IsCubemapTextureTarget(target));
1050
1051 // ensure the underlying texture is created
1052 if (!ensureRenderTarget())
1053 {
1054 return NULL;
1055 }
1056
Brandon Jonescef06ff2014-08-05 13:27:48 -07001057 updateStorageFaceLevel(layer, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001058
1059 // ensure this is a depth texture
Brandon Jonescef06ff2014-08-05 13:27:48 -07001060 if (!isDepth(level, layer))
Brandon Jones0511e802014-07-14 16:27:26 -07001061 {
1062 return NULL;
1063 }
1064
1065 return mTexStorage->getRenderTarget(target, level);
1066}
1067
Brandon Jones0511e802014-07-14 16:27:26 -07001068void TextureD3D_Cube::initializeStorage(bool renderTarget)
1069{
1070 // Only initialize the first time this texture is used as a render target or shader resource
1071 if (mTexStorage)
1072 {
1073 return;
1074 }
1075
1076 // do not attempt to create storage for nonexistant data
1077 if (!isFaceLevelComplete(0, 0))
1078 {
1079 return;
1080 }
1081
1082 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1083
1084 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1085 ASSERT(mTexStorage);
1086
1087 // flush image data to the storage
1088 updateStorage();
1089}
1090
1091TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1092{
1093 GLsizei size = getBaseLevelWidth();
1094
1095 ASSERT(size > 0);
1096
1097 // use existing storage level count, when previously specified by TexStorage*D
1098 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1099
1100 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1101}
1102
1103void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1104{
1105 SafeDelete(mTexStorage);
1106 mTexStorage = newCompleteTexStorage;
1107
1108 if (mTexStorage && mTexStorage->isManaged())
1109 {
1110 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1111 {
1112 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1113 {
1114 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1115 }
1116 }
1117 }
1118
1119 mDirtyImages = true;
1120}
1121
1122void TextureD3D_Cube::updateStorage()
1123{
1124 ASSERT(mTexStorage != NULL);
1125 GLint storageLevels = mTexStorage->getLevelCount();
1126 for (int face = 0; face < 6; face++)
1127 {
1128 for (int level = 0; level < storageLevels; level++)
1129 {
1130 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1131 {
1132 updateStorageFaceLevel(face, level);
1133 }
1134 }
1135 }
1136}
1137
1138bool TextureD3D_Cube::ensureRenderTarget()
1139{
1140 initializeStorage(true);
1141
1142 if (getBaseLevelWidth() > 0)
1143 {
1144 ASSERT(mTexStorage);
1145 if (!mTexStorage->isRenderTarget())
1146 {
1147 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1148
1149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1150 {
1151 delete newRenderTargetStorage;
1152 return gl::error(GL_OUT_OF_MEMORY, false);
1153 }
1154
1155 setCompleteTexStorage(newRenderTargetStorage);
1156 }
1157 }
1158
1159 return (mTexStorage && mTexStorage->isRenderTarget());
1160}
1161
1162TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1163{
1164 return mTexStorage;
1165}
1166
1167const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1168{
1169 // Note: if we are not cube-complete, there is no single base level image that can describe all
1170 // cube faces, so this method is only well-defined for a cube-complete base level.
1171 return mImageArray[0][0];
1172}
1173
Brandon Jones0511e802014-07-14 16:27:26 -07001174bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1175{
1176 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1177}
1178
Brandon Jones0511e802014-07-14 16:27:26 -07001179bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1180{
1181 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1182
1183 if (isImmutable())
1184 {
1185 return true;
1186 }
1187
1188 int baseSize = getBaseLevelWidth();
1189
1190 if (baseSize <= 0)
1191 {
1192 return false;
1193 }
1194
1195 // "isCubeComplete" checks for base level completeness and we must call that
1196 // to determine if any face at level 0 is complete. We omit that check here
1197 // to avoid re-checking cube-completeness for every face at level 0.
1198 if (level == 0)
1199 {
1200 return true;
1201 }
1202
1203 // Check that non-zero levels are consistent with the base level.
1204 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1205
1206 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1207 {
1208 return false;
1209 }
1210
1211 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1212 {
1213 return false;
1214 }
1215
1216 return true;
1217}
1218
1219void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1220{
1221 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1222 ImageD3D *image = mImageArray[faceIndex][level];
1223
1224 if (image->isDirty())
1225 {
1226 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1227 }
1228}
1229
1230void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1231{
1232 // If there currently is a corresponding storage texture image, it has these parameters
1233 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1234 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1235 const GLenum storageFormat = getBaseLevelInternalFormat();
1236
1237 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1238
1239 if (mTexStorage)
1240 {
1241 const int storageLevels = mTexStorage->getLevelCount();
1242
1243 if ((level >= storageLevels && storageLevels != 0) ||
1244 width != storageWidth ||
1245 height != storageHeight ||
1246 internalformat != storageFormat) // Discard mismatched storage
1247 {
1248 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1249 {
1250 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1251 {
1252 mImageArray[faceIndex][level]->markDirty();
1253 }
1254 }
1255
1256 SafeDelete(mTexStorage);
1257
1258 mDirtyImages = true;
1259 }
1260 }
1261}
1262
1263void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1264{
1265 if (isValidFaceLevel(faceIndex, level))
1266 {
1267 ImageD3D *image = mImageArray[faceIndex][level];
1268 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1269 image->markClean();
1270 }
1271}
1272
Brandon Jones78b1acd2014-07-15 15:33:07 -07001273
1274TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001275 : TextureD3D(renderer),
Brandon Jones78b1acd2014-07-15 15:33:07 -07001276 mTexStorage(NULL)
1277{
1278 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1279 {
1280 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1281 }
1282}
1283
1284TextureD3D_3D::~TextureD3D_3D()
1285{
1286 SafeDelete(mTexStorage);
1287
1288 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1289 {
1290 delete mImageArray[i];
1291 }
1292}
1293
Brandon Jonescef06ff2014-08-05 13:27:48 -07001294Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001295{
1296 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001297 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001298 return mImageArray[level];
1299}
1300
Brandon Jonescef06ff2014-08-05 13:27:48 -07001301GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001302{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001303 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1304 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001305}
1306
Brandon Jones78b1acd2014-07-15 15:33:07 -07001307GLsizei TextureD3D_3D::getWidth(GLint level) const
1308{
1309 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1310 return mImageArray[level]->getWidth();
1311 else
1312 return 0;
1313}
1314
1315GLsizei TextureD3D_3D::getHeight(GLint level) const
1316{
1317 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1318 return mImageArray[level]->getHeight();
1319 else
1320 return 0;
1321}
1322
1323GLsizei TextureD3D_3D::getDepth(GLint level) const
1324{
1325 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1326 return mImageArray[level]->getDepth();
1327 else
1328 return 0;
1329}
1330
1331GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1332{
1333 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1334 return mImageArray[level]->getInternalFormat();
1335 else
1336 return GL_NONE;
1337}
1338
1339bool TextureD3D_3D::isDepth(GLint level) const
1340{
Geoff Lang5d601382014-07-22 15:14:06 -04001341 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001342}
1343
Brandon Jonescef06ff2014-08-05 13:27:48 -07001344void TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001345{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001346 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001347 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1348
Brandon Jones78b1acd2014-07-15 15:33:07 -07001349 redefineImage(level, sizedInternalFormat, width, height, depth);
1350
1351 bool fastUnpacked = false;
1352
1353 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1354 if (isFastUnpackable(unpack, sizedInternalFormat))
1355 {
1356 // Will try to create RT storage if it does not exist
1357 RenderTarget *destRenderTarget = getRenderTarget(level);
1358 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1359
1360 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1361 {
1362 // Ensure we don't overwrite our newly initialized data
1363 mImageArray[level]->markClean();
1364
1365 fastUnpacked = true;
1366 }
1367 }
1368
1369 if (!fastUnpacked)
1370 {
1371 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1372 }
1373}
1374
Brandon Jonescef06ff2014-08-05 13:27:48 -07001375void TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001376{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001377 ASSERT(target == GL_TEXTURE_3D);
1378
Brandon Jones78b1acd2014-07-15 15:33:07 -07001379 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1380 redefineImage(level, format, width, height, depth);
1381
1382 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1383}
1384
Brandon Jonescef06ff2014-08-05 13:27:48 -07001385void TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001386{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001387 ASSERT(target == GL_TEXTURE_3D);
1388
Brandon Jones78b1acd2014-07-15 15:33:07 -07001389 bool fastUnpacked = false;
1390
1391 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1392 if (isFastUnpackable(unpack, getInternalFormat(level)))
1393 {
1394 RenderTarget *destRenderTarget = getRenderTarget(level);
1395 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1396
1397 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1398 {
1399 // Ensure we don't overwrite our newly initialized data
1400 mImageArray[level]->markClean();
1401
1402 fastUnpacked = true;
1403 }
1404 }
1405
1406 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1407 {
1408 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1409 }
1410}
1411
Brandon Jonescef06ff2014-08-05 13:27:48 -07001412void TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001413{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001414 ASSERT(target == GL_TEXTURE_3D);
1415
Brandon Jones78b1acd2014-07-15 15:33:07 -07001416 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1417 {
1418 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1419 }
1420}
1421
Brandon Jonescef06ff2014-08-05 13:27:48 -07001422void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1423{
1424 UNIMPLEMENTED();
1425}
1426
Brandon Jones78b1acd2014-07-15 15:33:07 -07001427void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1428{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001429 ASSERT(target == GL_TEXTURE_3D);
1430
Brandon Jones78b1acd2014-07-15 15:33:07 -07001431 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1432 // the current level we're copying to is defined (with appropriate format, width & height)
1433 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1434
1435 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1436 {
1437 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1438 mDirtyImages = true;
1439 }
1440 else
1441 {
1442 ensureRenderTarget();
1443
1444 if (isValidLevel(level))
1445 {
1446 updateStorageLevel(level);
1447
1448 gl::Rectangle sourceRect;
1449 sourceRect.x = x;
1450 sourceRect.width = width;
1451 sourceRect.y = y;
1452 sourceRect.height = height;
1453
1454 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001455 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001456 xoffset, yoffset, zoffset, mTexStorage, level);
1457 }
1458 }
1459}
1460
Brandon Jonescef06ff2014-08-05 13:27:48 -07001461void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001462{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001463 ASSERT(target == GL_TEXTURE_3D);
1464
Brandon Jones78b1acd2014-07-15 15:33:07 -07001465 for (int level = 0; level < levels; level++)
1466 {
1467 GLsizei levelWidth = std::max(1, width >> level);
1468 GLsizei levelHeight = std::max(1, height >> level);
1469 GLsizei levelDepth = std::max(1, depth >> level);
1470 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1471 }
1472
1473 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1474 {
1475 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1476 }
1477
1478 mImmutable = true;
1479
1480 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1481}
1482
Brandon Jones6053a522014-07-25 16:22:09 -07001483void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001484{
Brandon Jones6053a522014-07-25 16:22:09 -07001485 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001486}
1487
Brandon Jones6053a522014-07-25 16:22:09 -07001488void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001489{
Brandon Jones6053a522014-07-25 16:22:09 -07001490 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001491}
1492
Brandon Jones6053a522014-07-25 16:22:09 -07001493
Brandon Jones78b1acd2014-07-15 15:33:07 -07001494void TextureD3D_3D::generateMipmaps()
1495{
1496 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1497 int levelCount = mipLevels();
1498 for (int level = 1; level < levelCount; level++)
1499 {
1500 redefineImage(level, getBaseLevelInternalFormat(),
1501 std::max(getBaseLevelWidth() >> level, 1),
1502 std::max(getBaseLevelHeight() >> level, 1),
1503 std::max(getBaseLevelDepth() >> level, 1));
1504 }
1505
1506 if (mTexStorage && mTexStorage->isRenderTarget())
1507 {
1508 for (int level = 1; level < levelCount; level++)
1509 {
1510 mTexStorage->generateMipmap(level);
1511
1512 mImageArray[level]->markClean();
1513 }
1514 }
1515 else
1516 {
1517 for (int level = 1; level < levelCount; level++)
1518 {
1519 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1520 }
1521 }
1522}
1523
1524unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1525{
1526 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1527}
1528
1529RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1530{
1531 // ensure the underlying texture is created
1532 if (!ensureRenderTarget())
1533 {
1534 return NULL;
1535 }
1536
1537 updateStorageLevel(level);
1538
1539 // ensure this is NOT a depth texture
1540 if (isDepth(level))
1541 {
1542 return NULL;
1543 }
1544
1545 return mTexStorage->getRenderTarget(level);
1546}
1547
1548RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1549{
1550 // ensure the underlying texture is created
1551 if (!ensureRenderTarget())
1552 {
1553 return NULL;
1554 }
1555
1556 updateStorage();
1557
1558 // ensure this is NOT a depth texture
1559 if (isDepth(level))
1560 {
1561 return NULL;
1562 }
1563
1564 return mTexStorage->getRenderTarget(level, layer);
1565}
1566
1567RenderTarget *TextureD3D_3D::getDepthStencil(GLint level, GLint layer)
1568{
1569 // ensure the underlying texture is created
1570 if (!ensureRenderTarget())
1571 {
1572 return NULL;
1573 }
1574
1575 updateStorageLevel(level);
1576
1577 // ensure this is a depth texture
1578 if (!isDepth(level))
1579 {
1580 return NULL;
1581 }
1582
1583 return mTexStorage->getRenderTarget(level, layer);
1584}
1585
1586void TextureD3D_3D::initializeStorage(bool renderTarget)
1587{
1588 // Only initialize the first time this texture is used as a render target or shader resource
1589 if (mTexStorage)
1590 {
1591 return;
1592 }
1593
1594 // do not attempt to create storage for nonexistant data
1595 if (!isLevelComplete(0))
1596 {
1597 return;
1598 }
1599
1600 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1601
1602 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1603 ASSERT(mTexStorage);
1604
1605 // flush image data to the storage
1606 updateStorage();
1607}
1608
1609TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1610{
1611 GLsizei width = getBaseLevelWidth();
1612 GLsizei height = getBaseLevelHeight();
1613 GLsizei depth = getBaseLevelDepth();
1614
1615 ASSERT(width > 0 && height > 0 && depth > 0);
1616
1617 // use existing storage level count, when previously specified by TexStorage*D
1618 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1619
1620 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1621}
1622
1623void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1624{
1625 SafeDelete(mTexStorage);
1626 mTexStorage = newCompleteTexStorage;
1627 mDirtyImages = true;
1628
1629 // We do not support managed 3D storage, as that is D3D9/ES2-only
1630 ASSERT(!mTexStorage->isManaged());
1631}
1632
1633void TextureD3D_3D::updateStorage()
1634{
1635 ASSERT(mTexStorage != NULL);
1636 GLint storageLevels = mTexStorage->getLevelCount();
1637 for (int level = 0; level < storageLevels; level++)
1638 {
1639 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1640 {
1641 updateStorageLevel(level);
1642 }
1643 }
1644}
1645
1646bool TextureD3D_3D::ensureRenderTarget()
1647{
1648 initializeStorage(true);
1649
1650 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1651 {
1652 ASSERT(mTexStorage);
1653 if (!mTexStorage->isRenderTarget())
1654 {
1655 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1656
1657 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1658 {
1659 delete newRenderTargetStorage;
1660 return gl::error(GL_OUT_OF_MEMORY, false);
1661 }
1662
1663 setCompleteTexStorage(newRenderTargetStorage);
1664 }
1665 }
1666
1667 return (mTexStorage && mTexStorage->isRenderTarget());
1668}
1669
1670TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1671{
1672 return mTexStorage;
1673}
1674
1675const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1676{
1677 return mImageArray[0];
1678}
1679
1680bool TextureD3D_3D::isValidLevel(int level) const
1681{
1682 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1683}
1684
1685bool TextureD3D_3D::isLevelComplete(int level) const
1686{
1687 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1688
1689 if (isImmutable())
1690 {
1691 return true;
1692 }
1693
1694 GLsizei width = getBaseLevelWidth();
1695 GLsizei height = getBaseLevelHeight();
1696 GLsizei depth = getBaseLevelDepth();
1697
1698 if (width <= 0 || height <= 0 || depth <= 0)
1699 {
1700 return false;
1701 }
1702
1703 if (level == 0)
1704 {
1705 return true;
1706 }
1707
1708 ImageD3D *levelImage = mImageArray[level];
1709
1710 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1711 {
1712 return false;
1713 }
1714
1715 if (levelImage->getWidth() != std::max(1, width >> level))
1716 {
1717 return false;
1718 }
1719
1720 if (levelImage->getHeight() != std::max(1, height >> level))
1721 {
1722 return false;
1723 }
1724
1725 if (levelImage->getDepth() != std::max(1, depth >> level))
1726 {
1727 return false;
1728 }
1729
1730 return true;
1731}
1732
1733void TextureD3D_3D::updateStorageLevel(int level)
1734{
1735 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1736 ASSERT(isLevelComplete(level));
1737
1738 if (mImageArray[level]->isDirty())
1739 {
1740 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1741 }
1742}
1743
1744void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1745{
1746 // If there currently is a corresponding storage texture image, it has these parameters
1747 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1748 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1749 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1750 const GLenum storageFormat = getBaseLevelInternalFormat();
1751
1752 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1753
1754 if (mTexStorage)
1755 {
1756 const int storageLevels = mTexStorage->getLevelCount();
1757
1758 if ((level >= storageLevels && storageLevels != 0) ||
1759 width != storageWidth ||
1760 height != storageHeight ||
1761 depth != storageDepth ||
1762 internalformat != storageFormat) // Discard mismatched storage
1763 {
1764 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1765 {
1766 mImageArray[i]->markDirty();
1767 }
1768
1769 SafeDelete(mTexStorage);
1770 mDirtyImages = true;
1771 }
1772 }
1773}
1774
1775void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1776{
1777 if (isValidLevel(level))
1778 {
1779 ImageD3D *image = mImageArray[level];
1780 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1781 {
1782 image->markClean();
1783 }
1784 }
1785}
1786
Brandon Jones142ec422014-07-16 10:31:30 -07001787
1788TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Brandon Jones6053a522014-07-25 16:22:09 -07001789 : TextureD3D(renderer),
Brandon Jones142ec422014-07-16 10:31:30 -07001790 mTexStorage(NULL)
1791{
1792 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1793 {
1794 mLayerCounts[level] = 0;
1795 mImageArray[level] = NULL;
1796 }
1797}
1798
1799TextureD3D_2DArray::~TextureD3D_2DArray()
1800{
1801 SafeDelete(mTexStorage);
1802
1803 deleteImages();
1804}
1805
Brandon Jones142ec422014-07-16 10:31:30 -07001806Image *TextureD3D_2DArray::getImage(int level, int layer) const
1807{
1808 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1809 ASSERT(layer < mLayerCounts[level]);
1810 return mImageArray[level][layer];
1811}
1812
1813GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1814{
1815 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1816 return mLayerCounts[level];
1817}
1818
Brandon Jones142ec422014-07-16 10:31:30 -07001819GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1820{
1821 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1822}
1823
1824GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1825{
1826 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1827}
1828
1829GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1830{
1831 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1832}
1833
1834GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1835{
1836 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1837}
1838
1839bool TextureD3D_2DArray::isDepth(GLint level) const
1840{
Geoff Lang5d601382014-07-22 15:14:06 -04001841 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001842}
1843
Brandon Jonescef06ff2014-08-05 13:27:48 -07001844void TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001845{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001846 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1847
Geoff Lang5d601382014-07-22 15:14:06 -04001848 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1849
Brandon Jones142ec422014-07-16 10:31:30 -07001850 redefineImage(level, sizedInternalFormat, width, height, depth);
1851
Geoff Lang5d601382014-07-22 15:14:06 -04001852 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1853 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001854
1855 for (int i = 0; i < depth; i++)
1856 {
1857 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1858 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1859 }
1860}
1861
Brandon Jonescef06ff2014-08-05 13:27:48 -07001862void TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001863{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001864 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1865
Brandon Jones142ec422014-07-16 10:31:30 -07001866 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1867 redefineImage(level, format, width, height, depth);
1868
Geoff Lang5d601382014-07-22 15:14:06 -04001869 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1870 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001871
1872 for (int i = 0; i < depth; i++)
1873 {
1874 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1875 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1876 }
1877}
1878
Brandon Jonescef06ff2014-08-05 13:27:48 -07001879void TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001880{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001881 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1882
Geoff Lang5d601382014-07-22 15:14:06 -04001883 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1884 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001885
1886 for (int i = 0; i < depth; i++)
1887 {
1888 int layer = zoffset + i;
1889 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1890
1891 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
1892 {
1893 commitRect(level, xoffset, yoffset, layer, width, height);
1894 }
1895 }
1896}
1897
Brandon Jonescef06ff2014-08-05 13:27:48 -07001898void TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001899{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001900 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1901
Geoff Lang5d601382014-07-22 15:14:06 -04001902 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1903 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001904
1905 for (int i = 0; i < depth; i++)
1906 {
1907 int layer = zoffset + i;
1908 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1909
1910 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
1911 {
1912 commitRect(level, xoffset, yoffset, layer, width, height);
1913 }
1914 }
1915}
1916
Brandon Jonescef06ff2014-08-05 13:27:48 -07001917void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1918{
1919 UNIMPLEMENTED();
1920}
1921
Brandon Jones142ec422014-07-16 10:31:30 -07001922void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1923{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001924 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1925
Brandon Jones142ec422014-07-16 10:31:30 -07001926 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1927 // the current level we're copying to is defined (with appropriate format, width & height)
1928 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1929
1930 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1931 {
1932 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1933 mDirtyImages = true;
1934 }
1935 else
1936 {
1937 ensureRenderTarget();
1938
1939 if (isValidLevel(level))
1940 {
1941 updateStorageLevel(level);
1942
1943 gl::Rectangle sourceRect;
1944 sourceRect.x = x;
1945 sourceRect.width = width;
1946 sourceRect.y = y;
1947 sourceRect.height = height;
1948
Geoff Lang5d601382014-07-22 15:14:06 -04001949 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07001950 xoffset, yoffset, zoffset, mTexStorage, level);
1951 }
1952 }
1953}
1954
Brandon Jonescef06ff2014-08-05 13:27:48 -07001955void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07001956{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001957 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1958
Brandon Jones142ec422014-07-16 10:31:30 -07001959 deleteImages();
1960
1961 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1962 {
1963 GLsizei levelWidth = std::max(1, width >> level);
1964 GLsizei levelHeight = std::max(1, height >> level);
1965
1966 mLayerCounts[level] = (level < levels ? depth : 0);
1967
1968 if (mLayerCounts[level] > 0)
1969 {
1970 // Create new images for this level
1971 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
1972
1973 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1974 {
1975 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
1976 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1977 levelHeight, 1, true);
1978 }
1979 }
1980 }
1981
1982 mImmutable = true;
1983 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1984}
1985
Brandon Jones6053a522014-07-25 16:22:09 -07001986void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07001987{
Brandon Jones6053a522014-07-25 16:22:09 -07001988 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001989}
1990
Brandon Jones6053a522014-07-25 16:22:09 -07001991void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07001992{
Brandon Jones6053a522014-07-25 16:22:09 -07001993 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07001994}
1995
Brandon Jones6053a522014-07-25 16:22:09 -07001996
Brandon Jones142ec422014-07-16 10:31:30 -07001997void TextureD3D_2DArray::generateMipmaps()
1998{
1999 int baseWidth = getBaseLevelWidth();
2000 int baseHeight = getBaseLevelHeight();
2001 int baseDepth = getBaseLevelDepth();
2002 GLenum baseFormat = getBaseLevelInternalFormat();
2003
2004 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2005 int levelCount = mipLevels();
2006 for (int level = 1; level < levelCount; level++)
2007 {
2008 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2009 }
2010
2011 if (mTexStorage && mTexStorage->isRenderTarget())
2012 {
2013 for (int level = 1; level < levelCount; level++)
2014 {
2015 mTexStorage->generateMipmap(level);
2016
2017 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2018 {
2019 mImageArray[level][layer]->markClean();
2020 }
2021 }
2022 }
2023 else
2024 {
2025 for (int level = 1; level < levelCount; level++)
2026 {
2027 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2028 {
2029 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2030 }
2031 }
2032 }
2033}
2034
2035unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2036{
2037 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2038}
2039
2040RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2041{
2042 // ensure the underlying texture is created
2043 if (!ensureRenderTarget())
2044 {
2045 return NULL;
2046 }
2047
2048 updateStorageLevel(level);
2049
2050 // ensure this is NOT a depth texture
2051 if (isDepth(level))
2052 {
2053 return NULL;
2054 }
2055
2056 return mTexStorage->getRenderTarget(level, layer);
2057}
2058
2059RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer)
2060{
2061 // ensure the underlying texture is created
2062 if (!ensureRenderTarget())
2063 {
2064 return NULL;
2065 }
2066
2067 updateStorageLevel(level);
2068
2069 // ensure this is a depth texture
2070 if (!isDepth(level))
2071 {
2072 return NULL;
2073 }
2074
2075 return mTexStorage->getRenderTarget(level, layer);
2076}
2077
2078void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2079{
2080 // Only initialize the first time this texture is used as a render target or shader resource
2081 if (mTexStorage)
2082 {
2083 return;
2084 }
2085
2086 // do not attempt to create storage for nonexistant data
2087 if (!isLevelComplete(0))
2088 {
2089 return;
2090 }
2091
2092 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2093
2094 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2095 ASSERT(mTexStorage);
2096
2097 // flush image data to the storage
2098 updateStorage();
2099}
2100
2101TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2102{
2103 GLsizei width = getBaseLevelWidth();
2104 GLsizei height = getBaseLevelHeight();
2105 GLsizei depth = getLayers(0);
2106
2107 ASSERT(width > 0 && height > 0 && depth > 0);
2108
2109 // use existing storage level count, when previously specified by TexStorage*D
2110 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2111
2112 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2113}
2114
2115void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2116{
2117 SafeDelete(mTexStorage);
2118 mTexStorage = newCompleteTexStorage;
2119 mDirtyImages = true;
2120
2121 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2122 ASSERT(!mTexStorage->isManaged());
2123}
2124
2125void TextureD3D_2DArray::updateStorage()
2126{
2127 ASSERT(mTexStorage != NULL);
2128 GLint storageLevels = mTexStorage->getLevelCount();
2129 for (int level = 0; level < storageLevels; level++)
2130 {
2131 if (isLevelComplete(level))
2132 {
2133 updateStorageLevel(level);
2134 }
2135 }
2136}
2137
2138bool TextureD3D_2DArray::ensureRenderTarget()
2139{
2140 initializeStorage(true);
2141
2142 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2143 {
2144 ASSERT(mTexStorage);
2145 if (!mTexStorage->isRenderTarget())
2146 {
2147 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2148
2149 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2150 {
2151 delete newRenderTargetStorage;
2152 return gl::error(GL_OUT_OF_MEMORY, false);
2153 }
2154
2155 setCompleteTexStorage(newRenderTargetStorage);
2156 }
2157 }
2158
2159 return (mTexStorage && mTexStorage->isRenderTarget());
2160}
2161
2162const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2163{
2164 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2165}
2166
2167TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2168{
2169 return mTexStorage;
2170}
2171
2172bool TextureD3D_2DArray::isValidLevel(int level) const
2173{
2174 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2175}
2176
2177bool TextureD3D_2DArray::isLevelComplete(int level) const
2178{
2179 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2180
2181 if (isImmutable())
2182 {
2183 return true;
2184 }
2185
2186 GLsizei width = getBaseLevelWidth();
2187 GLsizei height = getBaseLevelHeight();
2188 GLsizei layers = getLayers(0);
2189
2190 if (width <= 0 || height <= 0 || layers <= 0)
2191 {
2192 return false;
2193 }
2194
2195 if (level == 0)
2196 {
2197 return true;
2198 }
2199
2200 if (getInternalFormat(level) != getInternalFormat(0))
2201 {
2202 return false;
2203 }
2204
2205 if (getWidth(level) != std::max(1, width >> level))
2206 {
2207 return false;
2208 }
2209
2210 if (getHeight(level) != std::max(1, height >> level))
2211 {
2212 return false;
2213 }
2214
2215 if (getLayers(level) != layers)
2216 {
2217 return false;
2218 }
2219
2220 return true;
2221}
2222
2223void TextureD3D_2DArray::updateStorageLevel(int level)
2224{
2225 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2226 ASSERT(isLevelComplete(level));
2227
2228 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2229 {
2230 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2231 if (mImageArray[level][layer]->isDirty())
2232 {
2233 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2234 }
2235 }
2236}
2237
2238void TextureD3D_2DArray::deleteImages()
2239{
2240 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2241 {
2242 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2243 {
2244 delete mImageArray[level][layer];
2245 }
2246 delete[] mImageArray[level];
2247 mImageArray[level] = NULL;
2248 mLayerCounts[level] = 0;
2249 }
2250}
2251
2252void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2253{
2254 // If there currently is a corresponding storage texture image, it has these parameters
2255 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2256 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2257 const int storageDepth = getLayers(0);
2258 const GLenum storageFormat = getBaseLevelInternalFormat();
2259
2260 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2261 {
2262 delete mImageArray[level][layer];
2263 }
2264 delete[] mImageArray[level];
2265 mImageArray[level] = NULL;
2266 mLayerCounts[level] = depth;
2267
2268 if (depth > 0)
2269 {
2270 mImageArray[level] = new ImageD3D*[depth]();
2271
2272 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2273 {
2274 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2275 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2276 }
2277 }
2278
2279 if (mTexStorage)
2280 {
2281 const int storageLevels = mTexStorage->getLevelCount();
2282
2283 if ((level >= storageLevels && storageLevels != 0) ||
2284 width != storageWidth ||
2285 height != storageHeight ||
2286 depth != storageDepth ||
2287 internalformat != storageFormat) // Discard mismatched storage
2288 {
2289 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2290 {
2291 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2292 {
2293 mImageArray[level][layer]->markDirty();
2294 }
2295 }
2296
2297 delete mTexStorage;
2298 mTexStorage = NULL;
2299 mDirtyImages = true;
2300 }
2301 }
2302}
2303
2304void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2305{
2306 if (isValidLevel(level) && layerTarget < getLayers(level))
2307 {
2308 ImageD3D *image = mImageArray[level][layerTarget];
2309 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2310 {
2311 image->markClean();
2312 }
2313 }
2314}
2315
Brandon Jones78b1acd2014-07-15 15:33:07 -07002316}