blob: a8134223919fe3d8f1563c4e3f850a7dc56a9407 [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{
298 return gl::GetDepthBits(getInternalFormat(level)) > 0;
299}
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{
303 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
304 : gl::GetSizedInternalFormat(format, type);
305 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,
417 gl::GetFormat(getBaseLevelInternalFormat()),
418 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.
495 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
496 {
497 if (samplerState.compareMode == GL_NONE)
498 {
499 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
500 samplerState.magFilter != GL_NEAREST)
501 {
502 return false;
503 }
504 }
505 }
506
507 return true;
508}
509
510void TextureD3D_2D::bindTexImage(egl::Surface *surface)
511{
512 GLenum internalformat = surface->getFormat();
513
514 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
515
516 if (mTexStorage)
517 {
518 SafeDelete(mTexStorage);
519 }
Brandon Jones78b1acd2014-07-15 15:33:07 -0700520 mTexStorage = new TextureStorageInterface2D(mRenderer, surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700521
522 mDirtyImages = true;
523}
524
525void TextureD3D_2D::releaseTexImage()
526{
527 if (mTexStorage)
528 {
529 SafeDelete(mTexStorage);
530 }
531
532 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
533 {
534 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
535 }
536}
537
538void TextureD3D_2D::generateMipmaps()
539{
540 int levelCount = mipLevels();
541
542 if (mTexStorage && mTexStorage->isRenderTarget())
543 {
544 for (int level = 1; level < levelCount; level++)
545 {
546 mTexStorage->generateMipmap(level);
547
548 mImageArray[level]->markClean();
549 }
550 }
551 else
552 {
553 for (int level = 1; level < levelCount; level++)
554 {
555 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
556 }
557 }
558}
559
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000560unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700561{
562 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
563}
564
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000565RenderTarget *TextureD3D_2D::getRenderTarget(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700566{
567 // ensure the underlying texture is created
568 if (!ensureRenderTarget())
569 {
570 return NULL;
571 }
572
573 updateStorageLevel(level);
574
575 // ensure this is NOT a depth texture
576 if (isDepth(level))
577 {
578 return NULL;
579 }
580
581 return mTexStorage->getRenderTarget(level);
582}
583
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000584RenderTarget *TextureD3D_2D::getDepthSencil(GLint level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700585{
586 // ensure the underlying texture is created
587 if (!ensureRenderTarget())
588 {
589 return NULL;
590 }
591
592 updateStorageLevel(level);
593
594 // ensure this is actually a depth texture
595 if (!isDepth(level))
596 {
597 return NULL;
598 }
599
600 return mTexStorage->getRenderTarget(level);
601}
602
603// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
604bool TextureD3D_2D::isMipmapComplete() const
605{
606 int levelCount = mipLevels();
607
608 for (int level = 0; level < levelCount; level++)
609 {
610 if (!isLevelComplete(level))
611 {
612 return false;
613 }
614 }
615
616 return true;
617}
618
619bool TextureD3D_2D::isValidLevel(int level) const
620{
621 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
622}
623
624bool TextureD3D_2D::isLevelComplete(int level) const
625{
626 if (isImmutable())
627 {
628 return true;
629 }
630
Brandon Jones78b1acd2014-07-15 15:33:07 -0700631 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632
633 GLsizei width = baseImage->getWidth();
634 GLsizei height = baseImage->getHeight();
635
636 if (width <= 0 || height <= 0)
637 {
638 return false;
639 }
640
641 // The base image level is complete if the width and height are positive
642 if (level == 0)
643 {
644 return true;
645 }
646
647 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700648 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700649
650 if (image->getInternalFormat() != baseImage->getInternalFormat())
651 {
652 return false;
653 }
654
655 if (image->getWidth() != std::max(1, width >> level))
656 {
657 return false;
658 }
659
660 if (image->getHeight() != std::max(1, height >> level))
661 {
662 return false;
663 }
664
665 return true;
666}
667
668// Constructs a native texture resource from the texture images
669void TextureD3D_2D::initializeStorage(bool renderTarget)
670{
671 // Only initialize the first time this texture is used as a render target or shader resource
672 if (mTexStorage)
673 {
674 return;
675 }
676
677 // do not attempt to create storage for nonexistant data
678 if (!isLevelComplete(0))
679 {
680 return;
681 }
682
683 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
684
685 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
686 ASSERT(mTexStorage);
687
688 // flush image data to the storage
689 updateStorage();
690}
691
Brandon Jones78b1acd2014-07-15 15:33:07 -0700692TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700693{
694 GLsizei width = getBaseLevelWidth();
695 GLsizei height = getBaseLevelHeight();
696
697 ASSERT(width > 0 && height > 0);
698
699 // use existing storage level count, when previously specified by TexStorage*D
700 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
701
Brandon Jones78b1acd2014-07-15 15:33:07 -0700702 return new TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700703}
704
705void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
706{
707 SafeDelete(mTexStorage);
708 mTexStorage = newCompleteTexStorage;
709
710 if (mTexStorage && mTexStorage->isManaged())
711 {
712 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
713 {
714 mImageArray[level]->setManagedSurface(mTexStorage, level);
715 }
716 }
717
718 mDirtyImages = true;
719}
720
721void TextureD3D_2D::updateStorage()
722{
723 ASSERT(mTexStorage != NULL);
724 GLint storageLevels = mTexStorage->getLevelCount();
725 for (int level = 0; level < storageLevels; level++)
726 {
727 if (mImageArray[level]->isDirty() && isLevelComplete(level))
728 {
729 updateStorageLevel(level);
730 }
731 }
732}
733
734bool TextureD3D_2D::ensureRenderTarget()
735{
736 initializeStorage(true);
737
738 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
739 {
740 ASSERT(mTexStorage);
741 if (!mTexStorage->isRenderTarget())
742 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700743 TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744
745 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
746 {
747 delete newRenderTargetStorage;
748 return gl::error(GL_OUT_OF_MEMORY, false);
749 }
750
751 setCompleteTexStorage(newRenderTargetStorage);
752 }
753 }
754
755 return (mTexStorage && mTexStorage->isRenderTarget());
756}
757
758TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
759{
760 return mTexStorage;
761}
762
763const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
764{
765 return mImageArray[0];
766}
767
768void TextureD3D_2D::updateStorageLevel(int level)
769{
770 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
771 ASSERT(isLevelComplete(level));
772
773 if (mImageArray[level]->isDirty())
774 {
775 commitRect(level, 0, 0, getWidth(level), getHeight(level));
776 }
777}
778
779void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
780{
781 // If there currently is a corresponding storage texture image, it has these parameters
782 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
783 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
784 const GLenum storageFormat = getBaseLevelInternalFormat();
785
786 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
787
788 if (mTexStorage)
789 {
790 const int storageLevels = mTexStorage->getLevelCount();
791
792 if ((level >= storageLevels && storageLevels != 0) ||
793 width != storageWidth ||
794 height != storageHeight ||
795 internalformat != storageFormat) // Discard mismatched storage
796 {
797 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
798 {
799 mImageArray[i]->markDirty();
800 }
801
802 SafeDelete(mTexStorage);
803 mDirtyImages = true;
804 }
805 }
806}
807
808void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
809{
810 if (isValidLevel(level))
811 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700812 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700813 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
814 {
815 image->markClean();
816 }
817 }
818}
819
Brandon Jones0511e802014-07-14 16:27:26 -0700820
Brandon Jones78b1acd2014-07-15 15:33:07 -0700821TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700822 : TextureCubeImpl(),
823 TextureD3D(renderer),
824 mTexStorage(NULL)
825{
826 for (int i = 0; i < 6; i++)
827 {
828 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
829 {
830 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
831 }
832 }
833}
834
835TextureD3D_Cube::~TextureD3D_Cube()
836{
837 SafeDelete(mTexStorage);
838
839 for (int i = 0; i < 6; i++)
840 {
841 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
842 {
843 SafeDelete(mImageArray[i][j]);
844 }
845 }
846}
847
848TextureD3D_Cube *TextureD3D_Cube::makeTextureD3D_Cube(TextureCubeImpl *texture)
849{
850 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_Cube*, texture));
851 return static_cast<TextureD3D_Cube*>(texture);
852}
853
854TextureStorageInterface *TextureD3D_Cube::getNativeTexture()
855{
856 // ensure the underlying texture is created
857 initializeStorage(false);
858
Brandon Jones78b1acd2014-07-15 15:33:07 -0700859 TextureStorageInterface *storage = getBaseLevelStorage();
Brandon Jones0511e802014-07-14 16:27:26 -0700860 if (storage)
861 {
862 updateStorage();
863 }
864
865 return storage;
866}
867
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000868Image *TextureD3D_Cube::getImage(GLenum target, int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700869{
870 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000871 return mImageArray[targetToIndex(target)][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700872}
873
874void TextureD3D_Cube::setUsage(GLenum usage)
875{
876 mUsage = usage;
877}
878
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000879GLenum TextureD3D_Cube::getInternalFormat(GLenum target, GLint level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700880{
881 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000882 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700883 else
884 return GL_NONE;
885}
886
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000887bool TextureD3D_Cube::isDepth(GLenum target, GLint level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700888{
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000889 return gl::GetDepthBits(getInternalFormat(target, level)) > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700890}
891
Jamie Madillf8bdfeb2014-07-31 18:31:28 +0000892void 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 -0700893{
894 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
895 : gl::GetSizedInternalFormat(format, type);
896
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);
Brandon Jones0511e802014-07-14 16:27:26 -0700932 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(format) ? format
933 : gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
934 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
989 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
990 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{
1505 return gl::GetDepthBits(getInternalFormat(level)) > 0;
1506}
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{
1510 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
1511 : gl::GetSizedInternalFormat(format, type);
1512 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,
1605 gl::GetFormat(getBaseLevelInternalFormat()),
1606 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{
2048 return gl::GetDepthBits(getInternalFormat(level)) > 0;
2049}
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{
2053 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
2054 : gl::GetSizedInternalFormat(format, type);
2055 redefineImage(level, sizedInternalFormat, width, height, depth);
2056
2057 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
2058
2059 for (int i = 0; i < depth; i++)
2060 {
2061 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2062 TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
2063 }
2064}
2065
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002066void 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 -07002067{
2068 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2069 redefineImage(level, format, width, height, depth);
2070
2071 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
2072
2073 for (int i = 0; i < depth; i++)
2074 {
2075 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2076 TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2077 }
2078}
2079
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002080void 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 -07002081{
2082 GLenum internalformat = getInternalFormat(level);
2083 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
2084
2085 for (int i = 0; i < depth; i++)
2086 {
2087 int layer = zoffset + i;
2088 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2089
2090 if (TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
2091 {
2092 commitRect(level, xoffset, yoffset, layer, width, height);
2093 }
2094 }
2095}
2096
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002097void 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 -07002098{
2099 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
2100
2101 for (int i = 0; i < depth; i++)
2102 {
2103 int layer = zoffset + i;
2104 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2105
2106 if (TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2107 {
2108 commitRect(level, xoffset, yoffset, layer, width, height);
2109 }
2110 }
2111}
2112
2113void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2114{
2115 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2116 // the current level we're copying to is defined (with appropriate format, width & height)
2117 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2118
2119 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2120 {
2121 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2122 mDirtyImages = true;
2123 }
2124 else
2125 {
2126 ensureRenderTarget();
2127
2128 if (isValidLevel(level))
2129 {
2130 updateStorageLevel(level);
2131
2132 gl::Rectangle sourceRect;
2133 sourceRect.x = x;
2134 sourceRect.width = width;
2135 sourceRect.y = y;
2136 sourceRect.height = height;
2137
2138 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
2139 xoffset, yoffset, zoffset, mTexStorage, level);
2140 }
2141 }
2142}
2143
Jamie Madillf8bdfeb2014-07-31 18:31:28 +00002144void TextureD3D_2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002145{
2146 deleteImages();
2147
2148 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2149 {
2150 GLsizei levelWidth = std::max(1, width >> level);
2151 GLsizei levelHeight = std::max(1, height >> level);
2152
2153 mLayerCounts[level] = (level < levels ? depth : 0);
2154
2155 if (mLayerCounts[level] > 0)
2156 {
2157 // Create new images for this level
2158 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2159
2160 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2161 {
2162 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2163 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2164 levelHeight, 1, true);
2165 }
2166 }
2167 }
2168
2169 mImmutable = true;
2170 setCompleteTexStorage(new TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
2171}
2172
2173bool TextureD3D_2DArray::isSamplerComplete(const gl::SamplerState &samplerState) const
2174{
2175 GLsizei width = getBaseLevelWidth();
2176 GLsizei height = getBaseLevelHeight();
2177 GLsizei depth = getLayers(0);
2178
2179 if (width <= 0 || height <= 0 || depth <= 0)
2180 {
2181 return false;
2182 }
2183
2184 // TODO(geofflang): use context's texture caps
2185 if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filterable)
2186 {
2187 if (samplerState.magFilter != GL_NEAREST ||
2188 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
2189 {
2190 return false;
2191 }
2192 }
2193
2194 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
2195 {
2196 return false;
2197 }
2198
2199 return true;
2200}
2201
2202bool TextureD3D_2DArray::isMipmapComplete() const
2203{
2204 int levelCount = mipLevels();
2205
2206 for (int level = 1; level < levelCount; level++)
2207 {
2208 if (!isLevelComplete(level))
2209 {
2210 return false;
2211 }
2212 }
2213
2214 return true;
2215}
2216
2217void TextureD3D_2DArray::generateMipmaps()
2218{
2219 int baseWidth = getBaseLevelWidth();
2220 int baseHeight = getBaseLevelHeight();
2221 int baseDepth = getBaseLevelDepth();
2222 GLenum baseFormat = getBaseLevelInternalFormat();
2223
2224 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2225 int levelCount = mipLevels();
2226 for (int level = 1; level < levelCount; level++)
2227 {
2228 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2229 }
2230
2231 if (mTexStorage && mTexStorage->isRenderTarget())
2232 {
2233 for (int level = 1; level < levelCount; level++)
2234 {
2235 mTexStorage->generateMipmap(level);
2236
2237 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2238 {
2239 mImageArray[level][layer]->markClean();
2240 }
2241 }
2242 }
2243 else
2244 {
2245 for (int level = 1; level < levelCount; level++)
2246 {
2247 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2248 {
2249 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2250 }
2251 }
2252 }
2253}
2254
2255unsigned int TextureD3D_2DArray::getRenderTargetSerial(GLint level, GLint layer)
2256{
2257 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
2258}
2259
2260RenderTarget *TextureD3D_2DArray::getRenderTarget(GLint level, GLint layer)
2261{
2262 // ensure the underlying texture is created
2263 if (!ensureRenderTarget())
2264 {
2265 return NULL;
2266 }
2267
2268 updateStorageLevel(level);
2269
2270 // ensure this is NOT a depth texture
2271 if (isDepth(level))
2272 {
2273 return NULL;
2274 }
2275
2276 return mTexStorage->getRenderTarget(level, layer);
2277}
2278
2279RenderTarget *TextureD3D_2DArray::getDepthStencil(GLint level, GLint layer)
2280{
2281 // ensure the underlying texture is created
2282 if (!ensureRenderTarget())
2283 {
2284 return NULL;
2285 }
2286
2287 updateStorageLevel(level);
2288
2289 // ensure this is a depth texture
2290 if (!isDepth(level))
2291 {
2292 return NULL;
2293 }
2294
2295 return mTexStorage->getRenderTarget(level, layer);
2296}
2297
2298void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2299{
2300 // Only initialize the first time this texture is used as a render target or shader resource
2301 if (mTexStorage)
2302 {
2303 return;
2304 }
2305
2306 // do not attempt to create storage for nonexistant data
2307 if (!isLevelComplete(0))
2308 {
2309 return;
2310 }
2311
2312 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2313
2314 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2315 ASSERT(mTexStorage);
2316
2317 // flush image data to the storage
2318 updateStorage();
2319}
2320
2321TextureStorageInterface2DArray *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
2322{
2323 GLsizei width = getBaseLevelWidth();
2324 GLsizei height = getBaseLevelHeight();
2325 GLsizei depth = getLayers(0);
2326
2327 ASSERT(width > 0 && height > 0 && depth > 0);
2328
2329 // use existing storage level count, when previously specified by TexStorage*D
2330 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2331
2332 return new TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
2333}
2334
2335void TextureD3D_2DArray::setCompleteTexStorage(TextureStorageInterface2DArray *newCompleteTexStorage)
2336{
2337 SafeDelete(mTexStorage);
2338 mTexStorage = newCompleteTexStorage;
2339 mDirtyImages = true;
2340
2341 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2342 ASSERT(!mTexStorage->isManaged());
2343}
2344
2345void TextureD3D_2DArray::updateStorage()
2346{
2347 ASSERT(mTexStorage != NULL);
2348 GLint storageLevels = mTexStorage->getLevelCount();
2349 for (int level = 0; level < storageLevels; level++)
2350 {
2351 if (isLevelComplete(level))
2352 {
2353 updateStorageLevel(level);
2354 }
2355 }
2356}
2357
2358bool TextureD3D_2DArray::ensureRenderTarget()
2359{
2360 initializeStorage(true);
2361
2362 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2363 {
2364 ASSERT(mTexStorage);
2365 if (!mTexStorage->isRenderTarget())
2366 {
2367 TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2368
2369 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
2370 {
2371 delete newRenderTargetStorage;
2372 return gl::error(GL_OUT_OF_MEMORY, false);
2373 }
2374
2375 setCompleteTexStorage(newRenderTargetStorage);
2376 }
2377 }
2378
2379 return (mTexStorage && mTexStorage->isRenderTarget());
2380}
2381
2382const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2383{
2384 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2385}
2386
2387TextureStorageInterface *TextureD3D_2DArray::getBaseLevelStorage()
2388{
2389 return mTexStorage;
2390}
2391
2392bool TextureD3D_2DArray::isValidLevel(int level) const
2393{
2394 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2395}
2396
2397bool TextureD3D_2DArray::isLevelComplete(int level) const
2398{
2399 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2400
2401 if (isImmutable())
2402 {
2403 return true;
2404 }
2405
2406 GLsizei width = getBaseLevelWidth();
2407 GLsizei height = getBaseLevelHeight();
2408 GLsizei layers = getLayers(0);
2409
2410 if (width <= 0 || height <= 0 || layers <= 0)
2411 {
2412 return false;
2413 }
2414
2415 if (level == 0)
2416 {
2417 return true;
2418 }
2419
2420 if (getInternalFormat(level) != getInternalFormat(0))
2421 {
2422 return false;
2423 }
2424
2425 if (getWidth(level) != std::max(1, width >> level))
2426 {
2427 return false;
2428 }
2429
2430 if (getHeight(level) != std::max(1, height >> level))
2431 {
2432 return false;
2433 }
2434
2435 if (getLayers(level) != layers)
2436 {
2437 return false;
2438 }
2439
2440 return true;
2441}
2442
2443void TextureD3D_2DArray::updateStorageLevel(int level)
2444{
2445 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2446 ASSERT(isLevelComplete(level));
2447
2448 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2449 {
2450 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2451 if (mImageArray[level][layer]->isDirty())
2452 {
2453 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2454 }
2455 }
2456}
2457
2458void TextureD3D_2DArray::deleteImages()
2459{
2460 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2461 {
2462 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2463 {
2464 delete mImageArray[level][layer];
2465 }
2466 delete[] mImageArray[level];
2467 mImageArray[level] = NULL;
2468 mLayerCounts[level] = 0;
2469 }
2470}
2471
2472void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2473{
2474 // If there currently is a corresponding storage texture image, it has these parameters
2475 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2476 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2477 const int storageDepth = getLayers(0);
2478 const GLenum storageFormat = getBaseLevelInternalFormat();
2479
2480 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2481 {
2482 delete mImageArray[level][layer];
2483 }
2484 delete[] mImageArray[level];
2485 mImageArray[level] = NULL;
2486 mLayerCounts[level] = depth;
2487
2488 if (depth > 0)
2489 {
2490 mImageArray[level] = new ImageD3D*[depth]();
2491
2492 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2493 {
2494 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2495 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2496 }
2497 }
2498
2499 if (mTexStorage)
2500 {
2501 const int storageLevels = mTexStorage->getLevelCount();
2502
2503 if ((level >= storageLevels && storageLevels != 0) ||
2504 width != storageWidth ||
2505 height != storageHeight ||
2506 depth != storageDepth ||
2507 internalformat != storageFormat) // Discard mismatched storage
2508 {
2509 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2510 {
2511 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2512 {
2513 mImageArray[level][layer]->markDirty();
2514 }
2515 }
2516
2517 delete mTexStorage;
2518 mTexStorage = NULL;
2519 mDirtyImages = true;
2520 }
2521 }
2522}
2523
2524void TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2525{
2526 if (isValidLevel(level) && layerTarget < getLayers(level))
2527 {
2528 ImageD3D *image = mImageArray[level][layerTarget];
2529 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
2530 {
2531 image->markClean();
2532 }
2533 }
2534}
2535
Brandon Jones78b1acd2014-07-15 15:33:07 -07002536}