blob: 4cbe5d65a1de274a3be06ddd40499a507568db82 [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"
15#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"
20#include "libGLESv2/renderer/d3d/ImageD3D.h"
21#include "libGLESv2/renderer/d3d/TextureD3D.h"
22#include "libGLESv2/renderer/d3d/TextureStorage.h"
23
24namespace rx
25{
26
27bool IsMipmapFiltered(const gl::SamplerState &samplerState)
28{
29 switch (samplerState.minFilter)
30 {
31 case GL_NEAREST:
32 case GL_LINEAR:
33 return false;
34 case GL_NEAREST_MIPMAP_NEAREST:
35 case GL_LINEAR_MIPMAP_NEAREST:
36 case GL_NEAREST_MIPMAP_LINEAR:
37 case GL_LINEAR_MIPMAP_LINEAR:
38 return true;
39 default: UNREACHABLE();
40 return false;
41 }
42}
43
44bool IsRenderTargetUsage(GLenum usage)
45{
46 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
47}
48
Brandon Jones78b1acd2014-07-15 15:33:07 -070049TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070050 : mRenderer(renderer),
51 mUsage(GL_NONE),
52 mDirtyImages(true),
53 mImmutable(false)
54{
55}
56
57TextureD3D::~TextureD3D()
58{
59}
60
Brandon Jones6b19b002014-07-16 14:32:05 -070061TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
62{
63 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
64 return static_cast<TextureD3D*>(texture);
65}
66
Brandon Jonesf47bebc2014-07-09 14:28:42 -070067GLint TextureD3D::getBaseLevelWidth() const
68{
Brandon Jones78b1acd2014-07-15 15:33:07 -070069 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070070 return (baseImage ? baseImage->getWidth() : 0);
71}
72
73GLint TextureD3D::getBaseLevelHeight() const
74{
Brandon Jones78b1acd2014-07-15 15:33:07 -070075 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070076 return (baseImage ? baseImage->getHeight() : 0);
77}
78
79GLint TextureD3D::getBaseLevelDepth() const
80{
Brandon Jones78b1acd2014-07-15 15:33:07 -070081 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070082 return (baseImage ? baseImage->getDepth() : 0);
83}
84
85// Note: "base level image" is loosely defined to be any image from the base level,
86// where in the base of 2D array textures and cube maps there are several. Don't use
87// the base level image for anything except querying texture format and size.
88GLenum TextureD3D::getBaseLevelInternalFormat() const
89{
Brandon Jones78b1acd2014-07-15 15:33:07 -070090 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070091 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
92}
93
Brandon Jones78b1acd2014-07-15 15:33:07 -070094void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070095{
96 // No-op
97 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
98 {
99 return;
100 }
101
102 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
103 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
104 const void *pixelData = pixels;
105
106 if (unpack.pixelBuffer.id() != 0)
107 {
108 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
109 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
110 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
111 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
112 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
113 const void *bufferData = pixelBuffer->getImplementation()->getData();
114 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
115 }
116
117 if (pixelData != NULL)
118 {
119 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
120 mDirtyImages = true;
121 }
122}
123
124bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700125 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700126{
127 const void *pixelData = pixels;
128
129 // CPU readback & copy where direct GPU copy is not supported
130 if (unpack.pixelBuffer.id() != 0)
131 {
132 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
133 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
134 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
135 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
136 const void *bufferData = pixelBuffer->getImplementation()->getData();
137 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
138 }
139
140 if (pixelData != NULL)
141 {
142 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
143 mDirtyImages = true;
144 }
145
146 return true;
147}
148
Brandon Jones78b1acd2014-07-15 15:33:07 -0700149void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700150{
151 if (pixels != NULL)
152 {
153 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
154 mDirtyImages = true;
155 }
156}
157
158bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700159 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700160{
161 if (pixels != NULL)
162 {
163 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
164 mDirtyImages = true;
165 }
166
167 return true;
168}
169
170bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
171{
172 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
173}
174
175bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700176 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700177{
178 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
179 {
180 return true;
181 }
182
183 // In order to perform the fast copy through the shader, we must have the right format, and be able
184 // to create a render target.
185 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
186
187 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
188
189 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
190}
191
192GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
193{
194 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
195 {
196 // Maximum number of levels
197 return gl::log2(std::max(std::max(width, height), depth)) + 1;
198 }
199 else
200 {
201 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
202 return 1;
203 }
204}
205
206int TextureD3D::mipLevels() const
207{
208 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
209}
210
211
Brandon Jones78b1acd2014-07-15 15:33:07 -0700212TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700213 : TextureD3D(renderer),
214 Texture2DImpl(),
215 mTexStorage(NULL)
216{
217 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
218 {
219 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
220 }
221}
222
223TextureD3D_2D::~TextureD3D_2D()
224{
225 SafeDelete(mTexStorage);
226
227 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
228 {
229 delete mImageArray[i];
230 }
231}
232
233TextureD3D_2D *TextureD3D_2D::makeTextureD3D_2D(Texture2DImpl *texture)
234{
235 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2D*, texture));
236 return static_cast<TextureD3D_2D*>(texture);
237}
238
239TextureStorageInterface *TextureD3D_2D::getNativeTexture()
240{
241 // ensure the underlying texture is created
242 initializeStorage(false);
243
Brandon Jones78b1acd2014-07-15 15:33:07 -0700244 TextureStorageInterface *storage = getBaseLevelStorage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700245 if (storage)
246 {
247 updateStorage();
248 }
249
250 return storage;
251}
252
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000253Image *TextureD3D_2D::getImage(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700254{
255 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
256 return mImageArray[level];
257}
258
259void TextureD3D_2D::setUsage(GLenum usage)
260{
261 mUsage = usage;
262}
263
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700264GLsizei TextureD3D_2D::getWidth(GLint level) const
265{
266 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
267 return mImageArray[level]->getWidth();
268 else
269 return 0;
270}
271
272GLsizei TextureD3D_2D::getHeight(GLint level) const
273{
274 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
275 return mImageArray[level]->getHeight();
276 else
277 return 0;
278}
279
280GLenum TextureD3D_2D::getInternalFormat(GLint level) const
281{
282 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
283 return mImageArray[level]->getInternalFormat();
284 else
285 return GL_NONE;
286}
287
288GLenum TextureD3D_2D::getActualFormat(GLint level) const
289{
290 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
291 return mImageArray[level]->getActualFormat();
292 else
293 return GL_NONE;
294}
295
296bool TextureD3D_2D::isDepth(GLint level) const
297{
Geoff Lang5d601382014-07-22 15:14:06 -0400298 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700299}
300
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000301void TextureD3D_2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700302{
Geoff Lang5d601382014-07-22 15:14:06 -0400303 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
304
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700305 bool fastUnpacked = false;
306
307 // Attempt a fast gpu copy of the pixel data to the surface
308 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
309 {
310 // Will try to create RT storage if it does not exist
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000311 RenderTarget *destRenderTarget = getRenderTarget(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700312 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
313
314 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
315 {
316 // Ensure we don't overwrite our newly initialized data
317 mImageArray[level]->markClean();
318
319 fastUnpacked = true;
320 }
321 }
322
323 if (!fastUnpacked)
324 {
325 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
326 }
327}
328
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000329void TextureD3D_2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700330{
331 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
332}
333
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000334void TextureD3D_2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700335{
336 bool fastUnpacked = false;
337
338 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
339 {
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000340 RenderTarget *renderTarget = getRenderTarget(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700341 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
342
343 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
344 {
345 // Ensure we don't overwrite our newly initialized data
346 mImageArray[level]->markClean();
347
348 fastUnpacked = true;
349 }
350 }
351
352 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
353 {
354 commitRect(level, xoffset, yoffset, width, height);
355 }
356}
357
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000358void TextureD3D_2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700359{
360 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
361 {
362 commitRect(level, xoffset, yoffset, width, height);
363 }
364}
365
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000366void TextureD3D_2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700367{
368 if (!mImageArray[level]->isRenderableFormat())
369 {
370 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
371 mDirtyImages = true;
372 }
373 else
374 {
375 ensureRenderTarget();
376 mImageArray[level]->markClean();
377
378 if (width != 0 && height != 0 && isValidLevel(level))
379 {
380 gl::Rectangle sourceRect;
381 sourceRect.x = x;
382 sourceRect.width = width;
383 sourceRect.y = y;
384 sourceRect.height = height;
385
386 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
387 }
388 }
389}
390
391void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
392{
393 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
394 // the current level we're copying to is defined (with appropriate format, width & height)
395 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
396
397 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
398 {
399 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
400 mDirtyImages = true;
401 }
402 else
403 {
404 ensureRenderTarget();
405
406 if (isValidLevel(level))
407 {
408 updateStorageLevel(level);
409
410 gl::Rectangle sourceRect;
411 sourceRect.x = x;
412 sourceRect.width = width;
413 sourceRect.y = y;
414 sourceRect.height = height;
415
416 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -0400417 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700418 xoffset, yoffset, mTexStorage, level);
419 }
420 }
421}
422
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000423void TextureD3D_2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700424{
425 for (int level = 0; level < levels; level++)
426 {
427 GLsizei levelWidth = std::max(1, width >> level);
428 GLsizei levelHeight = std::max(1, height >> level);
429 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
430 }
431
432 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
433 {
434 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
435 }
436
437 mImmutable = true;
438
Brandon Jones78b1acd2014-07-15 15:33:07 -0700439 setCompleteTexStorage(new TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440}
441
442// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
443bool TextureD3D_2D::isSamplerComplete(const gl::SamplerState &samplerState) const
444{
445 GLsizei width = getBaseLevelWidth();
446 GLsizei height = getBaseLevelHeight();
447
448 if (width <= 0 || height <= 0)
449 {
450 return false;
451 }
452
Geoff Lang6cf8e1b2014-07-03 13:03:57 -0400453 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filterable)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700454 {
455 if (samplerState.magFilter != GL_NEAREST ||
456 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
457 {
458 return false;
459 }
460 }
461
462 // TODO(geofflang): use context's extensions
463 bool npotSupport = mRenderer->getRendererExtensions().textureNPOT;
464
465 if (!npotSupport)
466 {
467 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
468 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
469 {
470 return false;
471 }
472 }
473
474 if (IsMipmapFiltered(samplerState))
475 {
476 if (!npotSupport)
477 {
478 if (!gl::isPow2(width) || !gl::isPow2(height))
479 {
480 return false;
481 }
482 }
483
484 if (!isMipmapComplete())
485 {
486 return false;
487 }
488 }
489
490 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
491 // The internalformat specified for the texture arrays is a sized internal depth or
492 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
493 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
494 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Lang5d601382014-07-22 15:14:06 -0400495 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(0));
496 if (formatInfo.depthBits > 0 && mRenderer->getCurrentClientVersion() > 2)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700497 {
498 if (samplerState.compareMode == GL_NONE)
499 {
500 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
501 samplerState.magFilter != GL_NEAREST)
502 {
503 return false;
504 }
505 }
506 }
507
508 return true;
509}
510
511void TextureD3D_2D::bindTexImage(egl::Surface *surface)
512{
513 GLenum internalformat = surface->getFormat();
514
515 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
516
517 if (mTexStorage)
518 {
519 SafeDelete(mTexStorage);
520 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700521 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522
523 mDirtyImages = true;
524}
525
526void TextureD3D_2D::releaseTexImage()
527{
528 if (mTexStorage)
529 {
530 SafeDelete(mTexStorage);
531 }
532
533 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
534 {
535 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
536 }
537}
538
539void TextureD3D_2D::generateMipmaps()
540{
541 int levelCount = mipLevels();
542
543 if (mTexStorage && mTexStorage->isRenderTarget())
544 {
545 for (int level = 1; level < levelCount; level++)
546 {
547 mTexStorage->generateMipmap(level);
548
549 mImageArray[level]->markClean();
550 }
551 }
552 else
553 {
554 for (int level = 1; level < levelCount; level++)
555 {
556 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
557 }
558 }
559}
560
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000561unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700562{
563 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
564}
565
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000566RenderTarget *TextureD3D_2D::getRenderTarget(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567{
568 // ensure the underlying texture is created
569 if (!ensureRenderTarget())
570 {
571 return NULL;
572 }
573
574 updateStorageLevel(level);
575
576 // ensure this is NOT a depth texture
577 if (isDepth(level))
578 {
579 return NULL;
580 }
581
582 return mTexStorage->getRenderTarget(level);
583}
584
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000585RenderTarget *TextureD3D_2D::getDepthSencil(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700586{
587 // ensure the underlying texture is created
588 if (!ensureRenderTarget())
589 {
590 return NULL;
591 }
592
593 updateStorageLevel(level);
594
595 // ensure this is actually a depth texture
596 if (!isDepth(level))
597 {
598 return NULL;
599 }
600
601 return mTexStorage->getRenderTarget(level);
602}
603
604// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
605bool TextureD3D_2D::isMipmapComplete() const
606{
607 int levelCount = mipLevels();
608
609 for (int level = 0; level < levelCount; level++)
610 {
611 if (!isLevelComplete(level))
612 {
613 return false;
614 }
615 }
616
617 return true;
618}
619
620bool TextureD3D_2D::isValidLevel(int level) const
621{
622 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
623}
624
625bool TextureD3D_2D::isLevelComplete(int level) const
626{
627 if (isImmutable())
628 {
629 return true;
630 }
631
Brandon Jones78b1acd2014-07-15 15:33:07 -0700632 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700633
634 GLsizei width = baseImage->getWidth();
635 GLsizei height = baseImage->getHeight();
636
637 if (width <= 0 || height <= 0)
638 {
639 return false;
640 }
641
642 // The base image level is complete if the width and height are positive
643 if (level == 0)
644 {
645 return true;
646 }
647
648 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700649 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700650
651 if (image->getInternalFormat() != baseImage->getInternalFormat())
652 {
653 return false;
654 }
655
656 if (image->getWidth() != std::max(1, width >> level))
657 {
658 return false;
659 }
660
661 if (image->getHeight() != std::max(1, height >> level))
662 {
663 return false;
664 }
665
666 return true;
667}
668
669// Constructs a native texture resource from the texture images
670void TextureD3D_2D::initializeStorage(bool renderTarget)
671{
672 // Only initialize the first time this texture is used as a render target or shader resource
673 if (mTexStorage)
674 {
675 return;
676 }
677
678 // do not attempt to create storage for nonexistant data
679 if (!isLevelComplete(0))
680 {
681 return;
682 }
683
684 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
685
686 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
687 ASSERT(mTexStorage);
688
689 // flush image data to the storage
690 updateStorage();
691}
692
Brandon Jones78b1acd2014-07-15 15:33:07 -0700693TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700694{
695 GLsizei width = getBaseLevelWidth();
696 GLsizei height = getBaseLevelHeight();
697
698 ASSERT(width > 0 && height > 0);
699
700 // use existing storage level count, when previously specified by TexStorage*D
701 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
702
Brandon Jones78b1acd2014-07-15 15:33:07 -0700703 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704}
705
706void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
707{
708 SafeDelete(mTexStorage);
709 mTexStorage = newCompleteTexStorage;
710
711 if (mTexStorage && mTexStorage->isManaged())
712 {
713 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
714 {
715 mImageArray[level]->setManagedSurface(mTexStorage, level);
716 }
717 }
718
719 mDirtyImages = true;
720}
721
722void TextureD3D_2D::updateStorage()
723{
724 ASSERT(mTexStorage != NULL);
725 GLint storageLevels = mTexStorage->getLevelCount();
726 for (int level = 0; level < storageLevels; level++)
727 {
728 if (mImageArray[level]->isDirty() && isLevelComplete(level))
729 {
730 updateStorageLevel(level);
731 }
732 }
733}
734
735bool TextureD3D_2D::ensureRenderTarget()
736{
737 initializeStorage(true);
738
739 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
740 {
741 ASSERT(mTexStorage);
742 if (!mTexStorage->isRenderTarget())
743 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700744 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700745
746 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
747 {
748 delete newRenderTargetStorage;
749 return gl::error(GL_OUT_OF_MEMORY, false);
750 }
751
752 setCompleteTexStorage(newRenderTargetStorage);
753 }
754 }
755
756 return (mTexStorage && mTexStorage->isRenderTarget());
757}
758
759TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
760{
761 return mTexStorage;
762}
763
764const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
765{
766 return mImageArray[0];
767}
768
769void TextureD3D_2D::updateStorageLevel(int level)
770{
771 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
772 ASSERT(isLevelComplete(level));
773
774 if (mImageArray[level]->isDirty())
775 {
776 commitRect(level, 0, 0, getWidth(level), getHeight(level));
777 }
778}
779
780void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
781{
782 // If there currently is a corresponding storage texture image, it has these parameters
783 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
784 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
785 const GLenum storageFormat = getBaseLevelInternalFormat();
786
787 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
788
789 if (mTexStorage)
790 {
791 const int storageLevels = mTexStorage->getLevelCount();
792
793 if ((level >= storageLevels && storageLevels != 0) ||
794 width != storageWidth ||
795 height != storageHeight ||
796 internalformat != storageFormat) // Discard mismatched storage
797 {
798 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
799 {
800 mImageArray[i]->markDirty();
801 }
802
803 SafeDelete(mTexStorage);
804 mDirtyImages = true;
805 }
806 }
807}
808
809void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
810{
811 if (isValidLevel(level))
812 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700813 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700814 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
815 {
816 image->markClean();
817 }
818 }
819}
820
Brandon Jones0511e802014-07-14 16:27:26 -0700821
Brandon Jones78b1acd2014-07-15 15:33:07 -0700822TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700823 : TextureCubeImpl(),
824 TextureD3D(renderer),
825 mTexStorage(NULL)
826{
827 for (int i = 0; i < 6; i++)
828 {
829 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
830 {
831 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
832 }
833 }
834}
835
836TextureD3D_Cube::~TextureD3D_Cube()
837{
838 SafeDelete(mTexStorage);
839
840 for (int i = 0; i < 6; i++)
841 {
842 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
843 {
844 SafeDelete(mImageArray[i][j]);
845 }
846 }
847}
848
849TextureD3D_Cube *TextureD3D_Cube::makeTextureD3D_Cube(TextureCubeImpl *texture)
850{
851 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_Cube*, texture));
852 return static_cast<TextureD3D_Cube*>(texture);
853}
854
855TextureStorageInterface *TextureD3D_Cube::getNativeTexture()
856{
857 // ensure the underlying texture is created
858 initializeStorage(false);
859
Brandon Jones78b1acd2014-07-15 15:33:07 -0700860 TextureStorageInterface *storage = getBaseLevelStorage();
Brandon Jones0511e802014-07-14 16:27:26 -0700861 if (storage)
862 {
863 updateStorage();
864 }
865
866 return storage;
867}
868
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000869Image *TextureD3D_Cube::getImage(GLenum target, int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700870{
871 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000872 return mImageArray[targetToIndex(target)][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700873}
874
875void TextureD3D_Cube::setUsage(GLenum usage)
876{
877 mUsage = usage;
878}
879
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000880GLenum TextureD3D_Cube::getInternalFormat(GLenum target, GLint level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700881{
882 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000883 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700884 else
885 return GL_NONE;
886}
887
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000888bool TextureD3D_Cube::isDepth(GLenum target, GLint level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700889{
Geoff Lang5d601382014-07-22 15:14:06 -0400890 return gl::GetInternalFormatInfo(getInternalFormat(target, level)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700891}
892
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000893void TextureD3D_Cube::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700894{
Geoff Lang5d601382014-07-22 15:14:06 -0400895 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700896
897 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
898
899 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
900}
901
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000902void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700903{
904 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000905 int faceIndex = targetToIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700906 redefineImage(faceIndex, level, format, width, height);
907
908 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
909}
910
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000911void TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700912{
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000913 int faceIndex = targetToIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700914 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
915 {
916 commitRect(faceIndex, level, xoffset, yoffset, width, height);
917 }
918}
919
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000920void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700921{
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000922 int faceIndex = targetToIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700923 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
924 {
925 commitRect(faceIndex, level, xoffset, yoffset, width, height);
926 }
927}
928
929void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
930{
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000931 int faceIndex = targetToIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400932 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
933
Brandon Jones0511e802014-07-14 16:27:26 -0700934 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
935
936 if (!mImageArray[faceIndex][level]->isRenderableFormat())
937 {
938 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
939 mDirtyImages = true;
940 }
941 else
942 {
943 ensureRenderTarget();
944 mImageArray[faceIndex][level]->markClean();
945
946 ASSERT(width == height);
947
948 if (width > 0 && isValidFaceLevel(faceIndex, level))
949 {
950 gl::Rectangle sourceRect;
951 sourceRect.x = x;
952 sourceRect.width = width;
953 sourceRect.y = y;
954 sourceRect.height = height;
955
956 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
957 }
958 }
959}
960
961void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
962{
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000963 int faceIndex = targetToIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -0700964
965 // We can only make our texture storage to a render target if the level we're copying *to* is complete
966 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
967 // rely on the "getBaseLevel*" methods reliably otherwise.
968 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
969
970 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
971 {
972 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
973 mDirtyImages = true;
974 }
975 else
976 {
977 ensureRenderTarget();
978
979 if (isValidFaceLevel(faceIndex, level))
980 {
981 updateStorageFaceLevel(faceIndex, level);
982
983 gl::Rectangle sourceRect;
984 sourceRect.x = x;
985 sourceRect.width = width;
986 sourceRect.y = y;
987 sourceRect.height = height;
988
Geoff Lang5d601382014-07-22 15:14:06 -0400989 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones0511e802014-07-14 16:27:26 -0700990 xoffset, yoffset, mTexStorage, target, level);
991 }
992 }
993}
994
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000995void TextureD3D_Cube::storage(GLsizei levels, GLenum internalformat, GLsizei size)
Brandon Jones0511e802014-07-14 16:27:26 -0700996{
997 for (int level = 0; level < levels; level++)
998 {
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000999 GLsizei mipSize = std::max(1, size >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001000 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1001 {
1002 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1003 }
1004 }
1005
1006 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1007 {
1008 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1009 {
1010 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1011 }
1012 }
1013
1014 mImmutable = true;
1015
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001016 setCompleteTexStorage(new TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
Brandon Jones0511e802014-07-14 16:27:26 -07001017}
1018
1019bool TextureD3D_Cube::isSamplerComplete(const gl::SamplerState &samplerState) const
1020{
1021 int size = getBaseLevelWidth();
1022
1023 bool mipmapping = IsMipmapFiltered(samplerState);
1024
1025 // TODO(geofflang): use context's texture caps
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001026 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filterable)
Brandon Jones0511e802014-07-14 16:27:26 -07001027 {
1028 if (samplerState.magFilter != GL_NEAREST ||
1029 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1030 {
1031 return false;
1032 }
1033 }
1034
1035 // TODO(geofflang): use context's extensions
1036 if (!gl::isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT)
1037 {
1038 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
1039 {
1040 return false;
1041 }
1042 }
1043
1044 if (!mipmapping)
1045 {
1046 if (!isCubeComplete())
1047 {
1048 return false;
1049 }
1050 }
1051 else
1052 {
1053 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1054 {
1055 return false;
1056 }
1057 }
1058
1059 return true;
1060}
1061
1062// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1063bool TextureD3D_Cube::isCubeComplete() const
1064{
1065 int baseWidth = getBaseLevelWidth();
1066 int baseHeight = getBaseLevelHeight();
1067 GLenum baseFormat = getBaseLevelInternalFormat();
1068
1069 if (baseWidth <= 0 || baseWidth != baseHeight)
1070 {
1071 return false;
1072 }
1073
1074 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1075 {
1076 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1077
1078 if (faceBaseImage.getWidth() != baseWidth ||
1079 faceBaseImage.getHeight() != baseHeight ||
1080 faceBaseImage.getInternalFormat() != baseFormat )
1081 {
1082 return false;
1083 }
1084 }
1085
1086 return true;
1087}
1088
1089void TextureD3D_Cube::generateMipmaps()
1090{
1091 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1092 int levelCount = mipLevels();
1093 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1094 {
1095 for (int level = 1; level < levelCount; level++)
1096 {
1097 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1098 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1099 }
1100 }
1101
1102 if (mTexStorage && mTexStorage->isRenderTarget())
1103 {
1104 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1105 {
1106 for (int level = 1; level < levelCount; level++)
1107 {
1108 mTexStorage->generateMipmap(faceIndex, level);
1109
1110 mImageArray[faceIndex][level]->markClean();
1111 }
1112 }
1113 }
1114 else
1115 {
1116 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1117 {
1118 for (int level = 1; level < levelCount; level++)
1119 {
1120 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1121 }
1122 }
1123 }
1124}
1125
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001126unsigned int TextureD3D_Cube::getRenderTargetSerial(GLenum target, GLint level)
Brandon Jones0511e802014-07-14 16:27:26 -07001127{
1128 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1129}
1130
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001131RenderTarget *TextureD3D_Cube::getRenderTarget(GLenum target, GLint level)
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
1133 ASSERT(gl::IsCubemapTextureTarget(target));
1134
1135 // ensure the underlying texture is created
1136 if (!ensureRenderTarget())
1137 {
1138 return NULL;
1139 }
1140
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001141 updateStorageFaceLevel(targetToIndex(target), level);
Brandon Jones0511e802014-07-14 16:27:26 -07001142
1143 // ensure this is NOT a depth texture
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001144 if (isDepth(target, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001145 {
1146 return NULL;
1147 }
1148
1149 return mTexStorage->getRenderTarget(target, level);
1150}
1151
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001152RenderTarget *TextureD3D_Cube::getDepthStencil(GLenum target, GLint level)
Brandon Jones0511e802014-07-14 16:27:26 -07001153{
1154 ASSERT(gl::IsCubemapTextureTarget(target));
1155
1156 // ensure the underlying texture is created
1157 if (!ensureRenderTarget())
1158 {
1159 return NULL;
1160 }
1161
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001162 updateStorageFaceLevel(targetToIndex(target), level);
Brandon Jones0511e802014-07-14 16:27:26 -07001163
1164 // ensure this is a depth texture
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001165 if (!isDepth(target, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001166 {
1167 return NULL;
1168 }
1169
1170 return mTexStorage->getRenderTarget(target, level);
1171}
1172
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001173int TextureD3D_Cube::targetToIndex(GLenum target)
1174{
1175 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1176 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1177 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1178 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1179 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1180
1181 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1182}
1183
Brandon Jones0511e802014-07-14 16:27:26 -07001184void TextureD3D_Cube::initializeStorage(bool renderTarget)
1185{
1186 // Only initialize the first time this texture is used as a render target or shader resource
1187 if (mTexStorage)
1188 {
1189 return;
1190 }
1191
1192 // do not attempt to create storage for nonexistant data
1193 if (!isFaceLevelComplete(0, 0))
1194 {
1195 return;
1196 }
1197
1198 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1199
1200 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1201 ASSERT(mTexStorage);
1202
1203 // flush image data to the storage
1204 updateStorage();
1205}
1206
1207TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1208{
1209 GLsizei size = getBaseLevelWidth();
1210
1211 ASSERT(size > 0);
1212
1213 // use existing storage level count, when previously specified by TexStorage*D
1214 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1215
1216 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1217}
1218
1219void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1220{
1221 SafeDelete(mTexStorage);
1222 mTexStorage = newCompleteTexStorage;
1223
1224 if (mTexStorage && mTexStorage->isManaged())
1225 {
1226 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1227 {
1228 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1229 {
1230 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1231 }
1232 }
1233 }
1234
1235 mDirtyImages = true;
1236}
1237
1238void TextureD3D_Cube::updateStorage()
1239{
1240 ASSERT(mTexStorage != NULL);
1241 GLint storageLevels = mTexStorage->getLevelCount();
1242 for (int face = 0; face < 6; face++)
1243 {
1244 for (int level = 0; level < storageLevels; level++)
1245 {
1246 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1247 {
1248 updateStorageFaceLevel(face, level);
1249 }
1250 }
1251 }
1252}
1253
1254bool TextureD3D_Cube::ensureRenderTarget()
1255{
1256 initializeStorage(true);
1257
1258 if (getBaseLevelWidth() > 0)
1259 {
1260 ASSERT(mTexStorage);
1261 if (!mTexStorage->isRenderTarget())
1262 {
1263 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1264
1265 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1266 {
1267 delete newRenderTargetStorage;
1268 return gl::error(GL_OUT_OF_MEMORY, false);
1269 }
1270
1271 setCompleteTexStorage(newRenderTargetStorage);
1272 }
1273 }
1274
1275 return (mTexStorage && mTexStorage->isRenderTarget());
1276}
1277
1278TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1279{
1280 return mTexStorage;
1281}
1282
1283const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1284{
1285 // Note: if we are not cube-complete, there is no single base level image that can describe all
1286 // cube faces, so this method is only well-defined for a cube-complete base level.
1287 return mImageArray[0][0];
1288}
1289
1290bool TextureD3D_Cube::isMipmapCubeComplete() const
1291{
1292 if (isImmutable())
1293 {
1294 return true;
1295 }
1296
1297 if (!isCubeComplete())
1298 {
1299 return false;
1300 }
1301
1302 int levelCount = mipLevels();
1303
1304 for (int face = 0; face < 6; face++)
1305 {
1306 for (int level = 1; level < levelCount; level++)
1307 {
1308 if (!isFaceLevelComplete(face, level))
1309 {
1310 return false;
1311 }
1312 }
1313 }
1314
1315 return true;
1316}
1317
1318bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1319{
1320 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1321}
1322
1323
1324bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1325{
1326 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1327
1328 if (isImmutable())
1329 {
1330 return true;
1331 }
1332
1333 int baseSize = getBaseLevelWidth();
1334
1335 if (baseSize <= 0)
1336 {
1337 return false;
1338 }
1339
1340 // "isCubeComplete" checks for base level completeness and we must call that
1341 // to determine if any face at level 0 is complete. We omit that check here
1342 // to avoid re-checking cube-completeness for every face at level 0.
1343 if (level == 0)
1344 {
1345 return true;
1346 }
1347
1348 // Check that non-zero levels are consistent with the base level.
1349 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1350
1351 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1352 {
1353 return false;
1354 }
1355
1356 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1357 {
1358 return false;
1359 }
1360
1361 return true;
1362}
1363
1364void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1365{
1366 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1367 ImageD3D *image = mImageArray[faceIndex][level];
1368
1369 if (image->isDirty())
1370 {
1371 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1372 }
1373}
1374
1375void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1376{
1377 // If there currently is a corresponding storage texture image, it has these parameters
1378 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1379 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1380 const GLenum storageFormat = getBaseLevelInternalFormat();
1381
1382 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1383
1384 if (mTexStorage)
1385 {
1386 const int storageLevels = mTexStorage->getLevelCount();
1387
1388 if ((level >= storageLevels && storageLevels != 0) ||
1389 width != storageWidth ||
1390 height != storageHeight ||
1391 internalformat != storageFormat) // Discard mismatched storage
1392 {
1393 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1394 {
1395 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1396 {
1397 mImageArray[faceIndex][level]->markDirty();
1398 }
1399 }
1400
1401 SafeDelete(mTexStorage);
1402
1403 mDirtyImages = true;
1404 }
1405 }
1406}
1407
1408void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1409{
1410 if (isValidFaceLevel(faceIndex, level))
1411 {
1412 ImageD3D *image = mImageArray[faceIndex][level];
1413 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1414 image->markClean();
1415 }
1416}
1417
Brandon Jones78b1acd2014-07-15 15:33:07 -07001418
1419TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
1420 : Texture3DImpl(),
1421 TextureD3D(renderer),
1422 mTexStorage(NULL)
1423{
1424 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1425 {
1426 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1427 }
1428}
1429
1430TextureD3D_3D::~TextureD3D_3D()
1431{
1432 SafeDelete(mTexStorage);
1433
1434 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1435 {
1436 delete mImageArray[i];
1437 }
1438}
1439
1440TextureD3D_3D *TextureD3D_3D::makeTextureD3D_3D(Texture3DImpl *texture)
1441{
1442 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_3D*, texture));
1443 return static_cast<TextureD3D_3D*>(texture);
1444}
1445
1446TextureStorageInterface *TextureD3D_3D::getNativeTexture()
1447{
1448 // ensure the underlying texture is created
1449 initializeStorage(false);
1450
1451 TextureStorageInterface *storage = getBaseLevelStorage();
1452 if (storage)
1453 {
1454 updateStorage();
1455 }
1456
1457 return storage;
1458}
1459
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001460Image *TextureD3D_3D::getImage(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001461{
1462 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1463 return mImageArray[level];
1464}
1465
1466void TextureD3D_3D::setUsage(GLenum usage)
1467{
1468 mUsage = usage;
1469}
1470
Brandon Jones78b1acd2014-07-15 15:33:07 -07001471GLsizei TextureD3D_3D::getWidth(GLint level) const
1472{
1473 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1474 return mImageArray[level]->getWidth();
1475 else
1476 return 0;
1477}
1478
1479GLsizei TextureD3D_3D::getHeight(GLint level) const
1480{
1481 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1482 return mImageArray[level]->getHeight();
1483 else
1484 return 0;
1485}
1486
1487GLsizei TextureD3D_3D::getDepth(GLint level) const
1488{
1489 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1490 return mImageArray[level]->getDepth();
1491 else
1492 return 0;
1493}
1494
1495GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1496{
1497 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1498 return mImageArray[level]->getInternalFormat();
1499 else
1500 return GL_NONE;
1501}
1502
1503bool TextureD3D_3D::isDepth(GLint level) const
1504{
Geoff Lang5d601382014-07-22 15:14:06 -04001505 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001506}
1507
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001508void TextureD3D_3D::setImage(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 -07001509{
Geoff Lang5d601382014-07-22 15:14:06 -04001510 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1511
Brandon Jones78b1acd2014-07-15 15:33:07 -07001512 redefineImage(level, sizedInternalFormat, width, height, depth);
1513
1514 bool fastUnpacked = false;
1515
1516 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1517 if (isFastUnpackable(unpack, sizedInternalFormat))
1518 {
1519 // Will try to create RT storage if it does not exist
1520 RenderTarget *destRenderTarget = getRenderTarget(level);
1521 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1522
1523 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1524 {
1525 // Ensure we don't overwrite our newly initialized data
1526 mImageArray[level]->markClean();
1527
1528 fastUnpacked = true;
1529 }
1530 }
1531
1532 if (!fastUnpacked)
1533 {
1534 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1535 }
1536}
1537
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001538void TextureD3D_3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001539{
1540 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1541 redefineImage(level, format, width, height, depth);
1542
1543 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
1544}
1545
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001546void TextureD3D_3D::subImage(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 -07001547{
1548 bool fastUnpacked = false;
1549
1550 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1551 if (isFastUnpackable(unpack, getInternalFormat(level)))
1552 {
1553 RenderTarget *destRenderTarget = getRenderTarget(level);
1554 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1555
1556 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1557 {
1558 // Ensure we don't overwrite our newly initialized data
1559 mImageArray[level]->markClean();
1560
1561 fastUnpacked = true;
1562 }
1563 }
1564
1565 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
1566 {
1567 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1568 }
1569}
1570
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001571void TextureD3D_3D::subImageCompressed(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 -07001572{
1573 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1574 {
1575 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1576 }
1577}
1578
1579void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1580{
1581 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1582 // the current level we're copying to is defined (with appropriate format, width & height)
1583 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1584
1585 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1586 {
1587 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1588 mDirtyImages = true;
1589 }
1590 else
1591 {
1592 ensureRenderTarget();
1593
1594 if (isValidLevel(level))
1595 {
1596 updateStorageLevel(level);
1597
1598 gl::Rectangle sourceRect;
1599 sourceRect.x = x;
1600 sourceRect.width = width;
1601 sourceRect.y = y;
1602 sourceRect.height = height;
1603
1604 mRenderer->copyImage(source, sourceRect,
Geoff Lang5d601382014-07-22 15:14:06 -04001605 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Brandon Jones78b1acd2014-07-15 15:33:07 -07001606 xoffset, yoffset, zoffset, mTexStorage, level);
1607 }
1608 }
1609}
1610
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00001611void TextureD3D_3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001612{
1613 for (int level = 0; level < levels; level++)
1614 {
1615 GLsizei levelWidth = std::max(1, width >> level);
1616 GLsizei levelHeight = std::max(1, height >> level);
1617 GLsizei levelDepth = std::max(1, depth >> level);
1618 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1619 }
1620
1621 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1622 {
1623 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1624 }
1625
1626 mImmutable = true;
1627
1628 setCompleteTexStorage(new TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
1629}
1630
1631bool TextureD3D_3D::isSamplerComplete(const gl::SamplerState &samplerState) const
1632{
1633 GLsizei width = getBaseLevelWidth();
1634 GLsizei height = getBaseLevelHeight();
1635 GLsizei depth = getBaseLevelDepth();
1636
1637 if (width <= 0 || height <= 0 || depth <= 0)
1638 {
1639 return false;
1640 }
1641
1642 // TODO(geofflang): use context's texture caps
Geoff Lang6cf8e1b2014-07-03 13:03:57 -04001643 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filterable)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001644 {
1645 if (samplerState.magFilter != GL_NEAREST ||
1646 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1647 {
1648 return false;
1649 }
1650 }
1651
1652 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
1653 {
1654 return false;
1655 }
1656
1657 return true;
1658}
1659
1660bool TextureD3D_3D::isMipmapComplete() const
1661{
1662 int levelCount = mipLevels();
1663
1664 for (int level = 0; level < levelCount; level++)
1665 {
1666 if (!isLevelComplete(level))
1667 {
1668 return false;
1669 }
1670 }
1671
1672 return true;
1673}
1674
1675void TextureD3D_3D::generateMipmaps()
1676{
1677 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1678 int levelCount = mipLevels();
1679 for (int level = 1; level < levelCount; level++)
1680 {
1681 redefineImage(level, getBaseLevelInternalFormat(),
1682 std::max(getBaseLevelWidth() >> level, 1),
1683 std::max(getBaseLevelHeight() >> level, 1),
1684 std::max(getBaseLevelDepth() >> level, 1));
1685 }
1686
1687 if (mTexStorage && mTexStorage->isRenderTarget())
1688 {
1689 for (int level = 1; level < levelCount; level++)
1690 {
1691 mTexStorage->generateMipmap(level);
1692
1693 mImageArray[level]->markClean();
1694 }
1695 }
1696 else
1697 {
1698 for (int level = 1; level < levelCount; level++)
1699 {
1700 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
1701 }
1702 }
1703}
1704
1705unsigned int TextureD3D_3D::getRenderTargetSerial(GLint level, GLint layer)
1706{
1707 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
1708}
1709
1710RenderTarget *TextureD3D_3D::getRenderTarget(GLint level)
1711{
1712 // ensure the underlying texture is created
1713 if (!ensureRenderTarget())
1714 {
1715 return NULL;
1716 }
1717
1718 updateStorageLevel(level);
1719
1720 // ensure this is NOT a depth texture
1721 if (isDepth(level))
1722 {
1723 return NULL;
1724 }
1725
1726 return mTexStorage->getRenderTarget(level);
1727}
1728
1729RenderTarget *TextureD3D_3D::getRenderTarget(GLint level, GLint layer)
1730{
1731 // ensure the underlying texture is created
1732 if (!ensureRenderTarget())
1733 {
1734 return NULL;
1735 }
1736
1737 updateStorage();
1738
1739 // ensure this is NOT a depth texture
1740 if (isDepth(level))
1741 {
1742 return NULL;
1743 }
1744
1745 return mTexStorage->getRenderTarget(level, layer);
1746}
1747
1748RenderTarget *TextureD3D_3D::getDepthStencil(GLint level, GLint layer)
1749{
1750 // ensure the underlying texture is created
1751 if (!ensureRenderTarget())
1752 {
1753 return NULL;
1754 }
1755
1756 updateStorageLevel(level);
1757
1758 // ensure this is a depth texture
1759 if (!isDepth(level))
1760 {
1761 return NULL;
1762 }
1763
1764 return mTexStorage->getRenderTarget(level, layer);
1765}
1766
1767void TextureD3D_3D::initializeStorage(bool renderTarget)
1768{
1769 // Only initialize the first time this texture is used as a render target or shader resource
1770 if (mTexStorage)
1771 {
1772 return;
1773 }
1774
1775 // do not attempt to create storage for nonexistant data
1776 if (!isLevelComplete(0))
1777 {
1778 return;
1779 }
1780
1781 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1782
1783 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1784 ASSERT(mTexStorage);
1785
1786 // flush image data to the storage
1787 updateStorage();
1788}
1789
1790TextureStorageInterface3D *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
1791{
1792 GLsizei width = getBaseLevelWidth();
1793 GLsizei height = getBaseLevelHeight();
1794 GLsizei depth = getBaseLevelDepth();
1795
1796 ASSERT(width > 0 && height > 0 && depth > 0);
1797
1798 // use existing storage level count, when previously specified by TexStorage*D
1799 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1800
1801 return new TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
1802}
1803
1804void TextureD3D_3D::setCompleteTexStorage(TextureStorageInterface3D *newCompleteTexStorage)
1805{
1806 SafeDelete(mTexStorage);
1807 mTexStorage = newCompleteTexStorage;
1808 mDirtyImages = true;
1809
1810 // We do not support managed 3D storage, as that is D3D9/ES2-only
1811 ASSERT(!mTexStorage->isManaged());
1812}
1813
1814void TextureD3D_3D::updateStorage()
1815{
1816 ASSERT(mTexStorage != NULL);
1817 GLint storageLevels = mTexStorage->getLevelCount();
1818 for (int level = 0; level < storageLevels; level++)
1819 {
1820 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1821 {
1822 updateStorageLevel(level);
1823 }
1824 }
1825}
1826
1827bool TextureD3D_3D::ensureRenderTarget()
1828{
1829 initializeStorage(true);
1830
1831 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1832 {
1833 ASSERT(mTexStorage);
1834 if (!mTexStorage->isRenderTarget())
1835 {
1836 TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1837
1838 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1839 {
1840 delete newRenderTargetStorage;
1841 return gl::error(GL_OUT_OF_MEMORY, false);
1842 }
1843
1844 setCompleteTexStorage(newRenderTargetStorage);
1845 }
1846 }
1847
1848 return (mTexStorage && mTexStorage->isRenderTarget());
1849}
1850
1851TextureStorageInterface *TextureD3D_3D::getBaseLevelStorage()
1852{
1853 return mTexStorage;
1854}
1855
1856const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1857{
1858 return mImageArray[0];
1859}
1860
1861bool TextureD3D_3D::isValidLevel(int level) const
1862{
1863 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1864}
1865
1866bool TextureD3D_3D::isLevelComplete(int level) const
1867{
1868 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1869
1870 if (isImmutable())
1871 {
1872 return true;
1873 }
1874
1875 GLsizei width = getBaseLevelWidth();
1876 GLsizei height = getBaseLevelHeight();
1877 GLsizei depth = getBaseLevelDepth();
1878
1879 if (width <= 0 || height <= 0 || depth <= 0)
1880 {
1881 return false;
1882 }
1883
1884 if (level == 0)
1885 {
1886 return true;
1887 }
1888
1889 ImageD3D *levelImage = mImageArray[level];
1890
1891 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1892 {
1893 return false;
1894 }
1895
1896 if (levelImage->getWidth() != std::max(1, width >> level))
1897 {
1898 return false;
1899 }
1900
1901 if (levelImage->getHeight() != std::max(1, height >> level))
1902 {
1903 return false;
1904 }
1905
1906 if (levelImage->getDepth() != std::max(1, depth >> level))
1907 {
1908 return false;
1909 }
1910
1911 return true;
1912}
1913
1914void TextureD3D_3D::updateStorageLevel(int level)
1915{
1916 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1917 ASSERT(isLevelComplete(level));
1918
1919 if (mImageArray[level]->isDirty())
1920 {
1921 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1922 }
1923}
1924
1925void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1926{
1927 // If there currently is a corresponding storage texture image, it has these parameters
1928 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1929 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1930 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1931 const GLenum storageFormat = getBaseLevelInternalFormat();
1932
1933 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1934
1935 if (mTexStorage)
1936 {
1937 const int storageLevels = mTexStorage->getLevelCount();
1938
1939 if ((level >= storageLevels && storageLevels != 0) ||
1940 width != storageWidth ||
1941 height != storageHeight ||
1942 depth != storageDepth ||
1943 internalformat != storageFormat) // Discard mismatched storage
1944 {
1945 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1946 {
1947 mImageArray[i]->markDirty();
1948 }
1949
1950 SafeDelete(mTexStorage);
1951 mDirtyImages = true;
1952 }
1953 }
1954}
1955
1956void TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1957{
1958 if (isValidLevel(level))
1959 {
1960 ImageD3D *image = mImageArray[level];
1961 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
1962 {
1963 image->markClean();
1964 }
1965 }
1966}
1967
Brandon Jones142ec422014-07-16 10:31:30 -07001968
1969TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
1970 : Texture2DArrayImpl(),
1971 TextureD3D(renderer),
1972 mTexStorage(NULL)
1973{
1974 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1975 {
1976 mLayerCounts[level] = 0;
1977 mImageArray[level] = NULL;
1978 }
1979}
1980
1981TextureD3D_2DArray::~TextureD3D_2DArray()
1982{
1983 SafeDelete(mTexStorage);
1984
1985 deleteImages();
1986}
1987
1988TextureD3D_2DArray *TextureD3D_2DArray::makeTextureD3D_2DArray(Texture2DArrayImpl *texture)
1989{
1990 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2DArray*, texture));
1991 return static_cast<TextureD3D_2DArray*>(texture);
1992}
1993
1994TextureStorageInterface *TextureD3D_2DArray::getNativeTexture()
1995{
1996 // ensure the underlying texture is created
1997 initializeStorage(false);
1998
1999 TextureStorageInterface *storage = getBaseLevelStorage();
2000 if (storage)
2001 {
2002 updateStorage();
2003 }
2004
2005 return storage;
2006}
2007
2008Image *TextureD3D_2DArray::getImage(int level, int layer) const
2009{
2010 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2011 ASSERT(layer < mLayerCounts[level]);
2012 return mImageArray[level][layer];
2013}
2014
2015GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2016{
2017 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2018 return mLayerCounts[level];
2019}
2020
2021void TextureD3D_2DArray::setUsage(GLenum usage)
2022{
2023 mUsage = usage;
2024}
2025
Brandon Jones142ec422014-07-16 10:31:30 -07002026GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2027{
2028 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2029}
2030
2031GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2032{
2033 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2034}
2035
2036GLsizei TextureD3D_2DArray::getLayers(GLint level) const
2037{
2038 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
2039}
2040
2041GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2042{
2043 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2044}
2045
2046bool TextureD3D_2DArray::isDepth(GLint level) const
2047{
Geoff Lang5d601382014-07-22 15:14:06 -04002048 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002049}
2050
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002051void TextureD3D_2DArray::setImage(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 -07002052{
Geoff Lang5d601382014-07-22 15:14:06 -04002053 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2054
Brandon Jones142ec422014-07-16 10:31:30 -07002055 redefineImage(level, sizedInternalFormat, width, height, depth);
2056
Geoff Lang5d601382014-07-22 15:14:06 -04002057 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2058 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002059
2060 for (int i = 0; i < depth; i++)
2061 {
2062 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2063 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2064 }
2065}
2066
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002067void TextureD3D_2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002068{
2069 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2070 redefineImage(level, format, width, height, depth);
2071
Geoff Lang5d601382014-07-22 15:14:06 -04002072 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2073 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002074
2075 for (int i = 0; i < depth; i++)
2076 {
2077 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2078 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2079 }
2080}
2081
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002082void TextureD3D_2DArray::subImage(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 -07002083{
Geoff Lang5d601382014-07-22 15:14:06 -04002084 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2085 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002086
2087 for (int i = 0; i < depth; i++)
2088 {
2089 int layer = zoffset + i;
2090 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2091
2092 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
2093 {
2094 commitRect(level, xoffset, yoffset, layer, width, height);
2095 }
2096 }
2097}
2098
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002099void TextureD3D_2DArray::subImageCompressed(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 -07002100{
Geoff Lang5d601382014-07-22 15:14:06 -04002101 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2102 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002103
2104 for (int i = 0; i < depth; i++)
2105 {
2106 int layer = zoffset + i;
2107 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2108
2109 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2110 {
2111 commitRect(level, xoffset, yoffset, layer, width, height);
2112 }
2113 }
2114}
2115
2116void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2117{
2118 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2119 // the current level we're copying to is defined (with appropriate format, width & height)
2120 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2121
2122 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2123 {
2124 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2125 mDirtyImages = true;
2126 }
2127 else
2128 {
2129 ensureRenderTarget();
2130
2131 if (isValidLevel(level))
2132 {
2133 updateStorageLevel(level);
2134
2135 gl::Rectangle sourceRect;
2136 sourceRect.x = x;
2137 sourceRect.width = width;
2138 sourceRect.y = y;
2139 sourceRect.height = height;
2140
Geoff Lang5d601382014-07-22 15:14:06 -04002141 mRenderer->copyImage(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
Brandon Jones142ec422014-07-16 10:31:30 -07002142 xoffset, yoffset, zoffset, mTexStorage, level);
2143 }
2144 }
2145}
2146
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002147void TextureD3D_2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002148{
2149 deleteImages();
2150
2151 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2152 {
2153 GLsizei levelWidth = std::max(1, width >> level);
2154 GLsizei levelHeight = std::max(1, height >> level);
2155
2156 mLayerCounts[level] = (level < levels ? depth : 0);
2157
2158 if (mLayerCounts[level] > 0)
2159 {
2160 // Create new images for this level
2161 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2162
2163 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2164 {
2165 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2166 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2167 levelHeight, 1, true);
2168 }
2169 }
2170 }
2171
2172 mImmutable = true;
2173 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
2174}
2175
2176bool TextureD3D_2DArray::isSamplerComplete(const gl::SamplerState &samplerState) const
2177{
2178 GLsizei width = getBaseLevelWidth();
2179 GLsizei height = getBaseLevelHeight();
2180 GLsizei depth = getLayers(0);
2181
2182 if (width <= 0 || height <= 0 || depth <= 0)
2183 {
2184 return false;
2185 }
2186
2187 // TODO(geofflang): use context's texture caps
2188 if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filterable)
2189 {
2190 if (samplerState.magFilter != GL_NEAREST ||
2191 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2192 {
2193 return false;
2194 }
2195 }
2196
2197 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
2198 {
2199 return false;
2200 }
2201
2202 return true;
2203}
2204
2205bool TextureD3D_2DArray::isMipmapComplete() const
2206{
2207 int levelCount = mipLevels();
2208
2209 for (int level = 1; level < levelCount; level++)
2210 {
2211 if (!isLevelComplete(level))
2212 {
2213 return false;
2214 }
2215 }
2216
2217 return true;
2218}
2219
2220void TextureD3D_2DArray::generateMipmaps()
2221{
2222 int baseWidth = getBaseLevelWidth();
2223 int baseHeight = getBaseLevelHeight();
2224 int baseDepth = getBaseLevelDepth();
2225 GLenum baseFormat = getBaseLevelInternalFormat();
2226
2227 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2228 int levelCount = mipLevels();
2229 for (int level = 1; level < levelCount; level++)
2230 {
2231 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2232 }
2233
2234 if (mTexStorage && mTexStorage->isRenderTarget())
2235 {
2236 for (int level = 1; level < levelCount; level++)
2237 {
2238 mTexStorage->generateMipmap(level);
2239
2240 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2241 {
2242 mImageArray[level][layer]->markClean();
2243 }
2244 }
2245 }
2246 else
2247 {
2248 for (int level = 1; level < levelCount; level++)
2249 {
2250 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2251 {
2252 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2253 }
2254 }
2255 }
2256}
2257
2258unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2259{
2260 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2261}
2262
2263RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2264{
2265 // ensure the underlying texture is created
2266 if (!ensureRenderTarget())
2267 {
2268 return NULL;
2269 }
2270
2271 updateStorageLevel(level);
2272
2273 // ensure this is NOT a depth texture
2274 if (isDepth(level))
2275 {
2276 return NULL;
2277 }
2278
2279 return mTexStorage->getRenderTarget(level, layer);
2280}
2281
2282RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer)
2283{
2284 // ensure the underlying texture is created
2285 if (!ensureRenderTarget())
2286 {
2287 return NULL;
2288 }
2289
2290 updateStorageLevel(level);
2291
2292 // ensure this is a depth texture
2293 if (!isDepth(level))
2294 {
2295 return NULL;
2296 }
2297
2298 return mTexStorage->getRenderTarget(level, layer);
2299}
2300
2301void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2302{
2303 // Only initialize the first time this texture is used as a render target or shader resource
2304 if (mTexStorage)
2305 {
2306 return;
2307 }
2308
2309 // do not attempt to create storage for nonexistant data
2310 if (!isLevelComplete(0))
2311 {
2312 return;
2313 }
2314
2315 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2316
2317 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2318 ASSERT(mTexStorage);
2319
2320 // flush image data to the storage
2321 updateStorage();
2322}
2323
2324TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2325{
2326 GLsizei width = getBaseLevelWidth();
2327 GLsizei height = getBaseLevelHeight();
2328 GLsizei depth = getLayers(0);
2329
2330 ASSERT(width > 0 && height > 0 && depth > 0);
2331
2332 // use existing storage level count, when previously specified by TexStorage*D
2333 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2334
2335 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2336}
2337
2338void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2339{
2340 SafeDelete(mTexStorage);
2341 mTexStorage = newCompleteTexStorage;
2342 mDirtyImages = true;
2343
2344 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2345 ASSERT(!mTexStorage->isManaged());
2346}
2347
2348void TextureD3D_2DArray::updateStorage()
2349{
2350 ASSERT(mTexStorage != NULL);
2351 GLint storageLevels = mTexStorage->getLevelCount();
2352 for (int level = 0; level < storageLevels; level++)
2353 {
2354 if (isLevelComplete(level))
2355 {
2356 updateStorageLevel(level);
2357 }
2358 }
2359}
2360
2361bool TextureD3D_2DArray::ensureRenderTarget()
2362{
2363 initializeStorage(true);
2364
2365 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2366 {
2367 ASSERT(mTexStorage);
2368 if (!mTexStorage->isRenderTarget())
2369 {
2370 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2371
2372 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2373 {
2374 delete newRenderTargetStorage;
2375 return gl::error(GL_OUT_OF_MEMORY, false);
2376 }
2377
2378 setCompleteTexStorage(newRenderTargetStorage);
2379 }
2380 }
2381
2382 return (mTexStorage && mTexStorage->isRenderTarget());
2383}
2384
2385const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2386{
2387 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2388}
2389
2390TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2391{
2392 return mTexStorage;
2393}
2394
2395bool TextureD3D_2DArray::isValidLevel(int level) const
2396{
2397 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2398}
2399
2400bool TextureD3D_2DArray::isLevelComplete(int level) const
2401{
2402 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2403
2404 if (isImmutable())
2405 {
2406 return true;
2407 }
2408
2409 GLsizei width = getBaseLevelWidth();
2410 GLsizei height = getBaseLevelHeight();
2411 GLsizei layers = getLayers(0);
2412
2413 if (width <= 0 || height <= 0 || layers <= 0)
2414 {
2415 return false;
2416 }
2417
2418 if (level == 0)
2419 {
2420 return true;
2421 }
2422
2423 if (getInternalFormat(level) != getInternalFormat(0))
2424 {
2425 return false;
2426 }
2427
2428 if (getWidth(level) != std::max(1, width >> level))
2429 {
2430 return false;
2431 }
2432
2433 if (getHeight(level) != std::max(1, height >> level))
2434 {
2435 return false;
2436 }
2437
2438 if (getLayers(level) != layers)
2439 {
2440 return false;
2441 }
2442
2443 return true;
2444}
2445
2446void TextureD3D_2DArray::updateStorageLevel(int level)
2447{
2448 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2449 ASSERT(isLevelComplete(level));
2450
2451 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2452 {
2453 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2454 if (mImageArray[level][layer]->isDirty())
2455 {
2456 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2457 }
2458 }
2459}
2460
2461void TextureD3D_2DArray::deleteImages()
2462{
2463 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2464 {
2465 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2466 {
2467 delete mImageArray[level][layer];
2468 }
2469 delete[] mImageArray[level];
2470 mImageArray[level] = NULL;
2471 mLayerCounts[level] = 0;
2472 }
2473}
2474
2475void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2476{
2477 // If there currently is a corresponding storage texture image, it has these parameters
2478 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2479 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2480 const int storageDepth = getLayers(0);
2481 const GLenum storageFormat = getBaseLevelInternalFormat();
2482
2483 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2484 {
2485 delete mImageArray[level][layer];
2486 }
2487 delete[] mImageArray[level];
2488 mImageArray[level] = NULL;
2489 mLayerCounts[level] = depth;
2490
2491 if (depth > 0)
2492 {
2493 mImageArray[level] = new ImageD3D*[depth]();
2494
2495 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2496 {
2497 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2498 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2499 }
2500 }
2501
2502 if (mTexStorage)
2503 {
2504 const int storageLevels = mTexStorage->getLevelCount();
2505
2506 if ((level >= storageLevels && storageLevels != 0) ||
2507 width != storageWidth ||
2508 height != storageHeight ||
2509 depth != storageDepth ||
2510 internalformat != storageFormat) // Discard mismatched storage
2511 {
2512 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2513 {
2514 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2515 {
2516 mImageArray[level][layer]->markDirty();
2517 }
2518 }
2519
2520 delete mTexStorage;
2521 mTexStorage = NULL;
2522 mDirtyImages = true;
2523 }
2524 }
2525}
2526
2527void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2528{
2529 if (isValidLevel(level) && layerTarget < getLayers(level))
2530 {
2531 ImageD3D *image = mImageArray[level][layerTarget];
2532 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2533 {
2534 image->markClean();
2535 }
2536 }
2537}
2538
Brandon Jones78b1acd2014-07-15 15:33:07 -07002539}