blob: 940dca2541b4bd300db70a76796799b6f4ea7e6e [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
49TextureD3D::TextureD3D(rx::Renderer *renderer)
50 : mRenderer(renderer),
51 mUsage(GL_NONE),
52 mDirtyImages(true),
53 mImmutable(false)
54{
55}
56
57TextureD3D::~TextureD3D()
58{
59}
60
61GLint TextureD3D::getBaseLevelWidth() const
62{
63 const rx::Image *baseImage = getBaseLevelImage();
64 return (baseImage ? baseImage->getWidth() : 0);
65}
66
67GLint TextureD3D::getBaseLevelHeight() const
68{
69 const rx::Image *baseImage = getBaseLevelImage();
70 return (baseImage ? baseImage->getHeight() : 0);
71}
72
73GLint TextureD3D::getBaseLevelDepth() const
74{
75 const rx::Image *baseImage = getBaseLevelImage();
76 return (baseImage ? baseImage->getDepth() : 0);
77}
78
79// Note: "base level image" is loosely defined to be any image from the base level,
80// where in the base of 2D array textures and cube maps there are several. Don't use
81// the base level image for anything except querying texture format and size.
82GLenum TextureD3D::getBaseLevelInternalFormat() const
83{
84 const rx::Image *baseImage = getBaseLevelImage();
85 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
86}
87
88void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
89{
90 // No-op
91 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
92 {
93 return;
94 }
95
96 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
97 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
98 const void *pixelData = pixels;
99
100 if (unpack.pixelBuffer.id() != 0)
101 {
102 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
103 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
104 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
105 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
106 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
107 const void *bufferData = pixelBuffer->getImplementation()->getData();
108 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
109 }
110
111 if (pixelData != NULL)
112 {
113 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
114 mDirtyImages = true;
115 }
116}
117
118bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
119 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, rx::Image *image)
120{
121 const void *pixelData = pixels;
122
123 // CPU readback & copy where direct GPU copy is not supported
124 if (unpack.pixelBuffer.id() != 0)
125 {
126 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
127 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
128 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
129 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
130 const void *bufferData = pixelBuffer->getImplementation()->getData();
131 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
132 }
133
134 if (pixelData != NULL)
135 {
136 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
137 mDirtyImages = true;
138 }
139
140 return true;
141}
142
143void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
144{
145 if (pixels != NULL)
146 {
147 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
148 mDirtyImages = true;
149 }
150}
151
152bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
153 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
154{
155 if (pixels != NULL)
156 {
157 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
158 mDirtyImages = true;
159 }
160
161 return true;
162}
163
164bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
165{
166 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
167}
168
169bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
170 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
171{
172 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
173 {
174 return true;
175 }
176
177 // In order to perform the fast copy through the shader, we must have the right format, and be able
178 // to create a render target.
179 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
180
181 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
182
183 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
184}
185
186GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
187{
188 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
189 {
190 // Maximum number of levels
191 return gl::log2(std::max(std::max(width, height), depth)) + 1;
192 }
193 else
194 {
195 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
196 return 1;
197 }
198}
199
200int TextureD3D::mipLevels() const
201{
202 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
203}
204
205
206TextureD3D_2D::TextureD3D_2D(rx::Renderer *renderer)
207 : TextureD3D(renderer),
208 Texture2DImpl(),
209 mTexStorage(NULL)
210{
211 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
212 {
213 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
214 }
215}
216
217TextureD3D_2D::~TextureD3D_2D()
218{
219 SafeDelete(mTexStorage);
220
221 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
222 {
223 delete mImageArray[i];
224 }
225}
226
227TextureD3D_2D *TextureD3D_2D::makeTextureD3D_2D(Texture2DImpl *texture)
228{
229 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2D*, texture));
230 return static_cast<TextureD3D_2D*>(texture);
231}
232
233TextureStorageInterface *TextureD3D_2D::getNativeTexture()
234{
235 // ensure the underlying texture is created
236 initializeStorage(false);
237
238 rx::TextureStorageInterface *storage = getBaseLevelStorage();
239 if (storage)
240 {
241 updateStorage();
242 }
243
244 return storage;
245}
246
247Image *TextureD3D_2D::getImage(int level) const
248{
249 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
250 return mImageArray[level];
251}
252
253void TextureD3D_2D::setUsage(GLenum usage)
254{
255 mUsage = usage;
256}
257
258void TextureD3D_2D::resetDirty()
259{
260 mDirtyImages = false;
261}
262
263GLsizei TextureD3D_2D::getWidth(GLint level) const
264{
265 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
266 return mImageArray[level]->getWidth();
267 else
268 return 0;
269}
270
271GLsizei TextureD3D_2D::getHeight(GLint level) const
272{
273 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
274 return mImageArray[level]->getHeight();
275 else
276 return 0;
277}
278
279GLenum TextureD3D_2D::getInternalFormat(GLint level) const
280{
281 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
282 return mImageArray[level]->getInternalFormat();
283 else
284 return GL_NONE;
285}
286
287GLenum TextureD3D_2D::getActualFormat(GLint level) const
288{
289 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
290 return mImageArray[level]->getActualFormat();
291 else
292 return GL_NONE;
293}
294
295bool TextureD3D_2D::isDepth(GLint level) const
296{
297 return gl::GetDepthBits(getInternalFormat(level)) > 0;
298}
299
300void TextureD3D_2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
301{
302 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
303 : gl::GetSizedInternalFormat(format, type);
304 bool fastUnpacked = false;
305
306 // Attempt a fast gpu copy of the pixel data to the surface
307 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
308 {
309 // Will try to create RT storage if it does not exist
310 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
311 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
312
313 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
314 {
315 // Ensure we don't overwrite our newly initialized data
316 mImageArray[level]->markClean();
317
318 fastUnpacked = true;
319 }
320 }
321
322 if (!fastUnpacked)
323 {
324 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
325 }
326}
327
328void TextureD3D_2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
329{
330 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
331}
332
333void TextureD3D_2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
334{
335 bool fastUnpacked = false;
336
337 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
338 {
339 rx::RenderTarget *renderTarget = getRenderTarget(level);
340 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
341
342 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
343 {
344 // Ensure we don't overwrite our newly initialized data
345 mImageArray[level]->markClean();
346
347 fastUnpacked = true;
348 }
349 }
350
351 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
352 {
353 commitRect(level, xoffset, yoffset, width, height);
354 }
355}
356
357void TextureD3D_2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
358{
359 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
360 {
361 commitRect(level, xoffset, yoffset, width, height);
362 }
363}
364
365void TextureD3D_2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
366{
367 if (!mImageArray[level]->isRenderableFormat())
368 {
369 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
370 mDirtyImages = true;
371 }
372 else
373 {
374 ensureRenderTarget();
375 mImageArray[level]->markClean();
376
377 if (width != 0 && height != 0 && isValidLevel(level))
378 {
379 gl::Rectangle sourceRect;
380 sourceRect.x = x;
381 sourceRect.width = width;
382 sourceRect.y = y;
383 sourceRect.height = height;
384
385 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
386 }
387 }
388}
389
390void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
391{
392 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
393 // the current level we're copying to is defined (with appropriate format, width & height)
394 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
395
396 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
397 {
398 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
399 mDirtyImages = true;
400 }
401 else
402 {
403 ensureRenderTarget();
404
405 if (isValidLevel(level))
406 {
407 updateStorageLevel(level);
408
409 gl::Rectangle sourceRect;
410 sourceRect.x = x;
411 sourceRect.width = width;
412 sourceRect.y = y;
413 sourceRect.height = height;
414
415 mRenderer->copyImage(source, sourceRect,
416 gl::GetFormat(getBaseLevelInternalFormat()),
417 xoffset, yoffset, mTexStorage, level);
418 }
419 }
420}
421
422void TextureD3D_2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
423{
424 for (int level = 0; level < levels; level++)
425 {
426 GLsizei levelWidth = std::max(1, width >> level);
427 GLsizei levelHeight = std::max(1, height >> level);
428 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
429 }
430
431 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
432 {
433 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
434 }
435
436 mImmutable = true;
437
438 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
439}
440
441// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
442bool TextureD3D_2D::isSamplerComplete(const gl::SamplerState &samplerState) const
443{
444 GLsizei width = getBaseLevelWidth();
445 GLsizei height = getBaseLevelHeight();
446
447 if (width <= 0 || height <= 0)
448 {
449 return false;
450 }
451
452 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
453 {
454 if (samplerState.magFilter != GL_NEAREST ||
455 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
456 {
457 return false;
458 }
459 }
460
461 // TODO(geofflang): use context's extensions
462 bool npotSupport = mRenderer->getRendererExtensions().textureNPOT;
463
464 if (!npotSupport)
465 {
466 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
467 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
468 {
469 return false;
470 }
471 }
472
473 if (IsMipmapFiltered(samplerState))
474 {
475 if (!npotSupport)
476 {
477 if (!gl::isPow2(width) || !gl::isPow2(height))
478 {
479 return false;
480 }
481 }
482
483 if (!isMipmapComplete())
484 {
485 return false;
486 }
487 }
488
489 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
490 // The internalformat specified for the texture arrays is a sized internal depth or
491 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
492 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
493 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
494 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
495 {
496 if (samplerState.compareMode == GL_NONE)
497 {
498 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
499 samplerState.magFilter != GL_NEAREST)
500 {
501 return false;
502 }
503 }
504 }
505
506 return true;
507}
508
509void TextureD3D_2D::bindTexImage(egl::Surface *surface)
510{
511 GLenum internalformat = surface->getFormat();
512
513 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
514
515 if (mTexStorage)
516 {
517 SafeDelete(mTexStorage);
518 }
519 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
520
521 mDirtyImages = true;
522}
523
524void TextureD3D_2D::releaseTexImage()
525{
526 if (mTexStorage)
527 {
528 SafeDelete(mTexStorage);
529 }
530
531 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
532 {
533 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
534 }
535}
536
537void TextureD3D_2D::generateMipmaps()
538{
539 int levelCount = mipLevels();
540
541 if (mTexStorage && mTexStorage->isRenderTarget())
542 {
543 for (int level = 1; level < levelCount; level++)
544 {
545 mTexStorage->generateMipmap(level);
546
547 mImageArray[level]->markClean();
548 }
549 }
550 else
551 {
552 for (int level = 1; level < levelCount; level++)
553 {
554 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
555 }
556 }
557}
558
559unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level)
560{
561 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
562}
563
564RenderTarget *TextureD3D_2D::getRenderTarget(GLint level)
565{
566 // ensure the underlying texture is created
567 if (!ensureRenderTarget())
568 {
569 return NULL;
570 }
571
572 updateStorageLevel(level);
573
574 // ensure this is NOT a depth texture
575 if (isDepth(level))
576 {
577 return NULL;
578 }
579
580 return mTexStorage->getRenderTarget(level);
581}
582
583RenderTarget *TextureD3D_2D::getDepthSencil(GLint level)
584{
585 // ensure the underlying texture is created
586 if (!ensureRenderTarget())
587 {
588 return NULL;
589 }
590
591 updateStorageLevel(level);
592
593 // ensure this is actually a depth texture
594 if (!isDepth(level))
595 {
596 return NULL;
597 }
598
599 return mTexStorage->getRenderTarget(level);
600}
601
602// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
603bool TextureD3D_2D::isMipmapComplete() const
604{
605 int levelCount = mipLevels();
606
607 for (int level = 0; level < levelCount; level++)
608 {
609 if (!isLevelComplete(level))
610 {
611 return false;
612 }
613 }
614
615 return true;
616}
617
618bool TextureD3D_2D::isValidLevel(int level) const
619{
620 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
621}
622
623bool TextureD3D_2D::isLevelComplete(int level) const
624{
625 if (isImmutable())
626 {
627 return true;
628 }
629
630 const rx::Image *baseImage = getBaseLevelImage();
631
632 GLsizei width = baseImage->getWidth();
633 GLsizei height = baseImage->getHeight();
634
635 if (width <= 0 || height <= 0)
636 {
637 return false;
638 }
639
640 // The base image level is complete if the width and height are positive
641 if (level == 0)
642 {
643 return true;
644 }
645
646 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
647 rx::Image *image = mImageArray[level];
648
649 if (image->getInternalFormat() != baseImage->getInternalFormat())
650 {
651 return false;
652 }
653
654 if (image->getWidth() != std::max(1, width >> level))
655 {
656 return false;
657 }
658
659 if (image->getHeight() != std::max(1, height >> level))
660 {
661 return false;
662 }
663
664 return true;
665}
666
667// Constructs a native texture resource from the texture images
668void TextureD3D_2D::initializeStorage(bool renderTarget)
669{
670 // Only initialize the first time this texture is used as a render target or shader resource
671 if (mTexStorage)
672 {
673 return;
674 }
675
676 // do not attempt to create storage for nonexistant data
677 if (!isLevelComplete(0))
678 {
679 return;
680 }
681
682 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
683
684 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
685 ASSERT(mTexStorage);
686
687 // flush image data to the storage
688 updateStorage();
689}
690
691rx::TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
692{
693 GLsizei width = getBaseLevelWidth();
694 GLsizei height = getBaseLevelHeight();
695
696 ASSERT(width > 0 && height > 0);
697
698 // use existing storage level count, when previously specified by TexStorage*D
699 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
700
701 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
702}
703
704void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
705{
706 SafeDelete(mTexStorage);
707 mTexStorage = newCompleteTexStorage;
708
709 if (mTexStorage && mTexStorage->isManaged())
710 {
711 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
712 {
713 mImageArray[level]->setManagedSurface(mTexStorage, level);
714 }
715 }
716
717 mDirtyImages = true;
718}
719
720void TextureD3D_2D::updateStorage()
721{
722 ASSERT(mTexStorage != NULL);
723 GLint storageLevels = mTexStorage->getLevelCount();
724 for (int level = 0; level < storageLevels; level++)
725 {
726 if (mImageArray[level]->isDirty() && isLevelComplete(level))
727 {
728 updateStorageLevel(level);
729 }
730 }
731}
732
733bool TextureD3D_2D::ensureRenderTarget()
734{
735 initializeStorage(true);
736
737 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
738 {
739 ASSERT(mTexStorage);
740 if (!mTexStorage->isRenderTarget())
741 {
742 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
743
744 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
745 {
746 delete newRenderTargetStorage;
747 return gl::error(GL_OUT_OF_MEMORY, false);
748 }
749
750 setCompleteTexStorage(newRenderTargetStorage);
751 }
752 }
753
754 return (mTexStorage && mTexStorage->isRenderTarget());
755}
756
757TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
758{
759 return mTexStorage;
760}
761
762const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
763{
764 return mImageArray[0];
765}
766
767void TextureD3D_2D::updateStorageLevel(int level)
768{
769 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
770 ASSERT(isLevelComplete(level));
771
772 if (mImageArray[level]->isDirty())
773 {
774 commitRect(level, 0, 0, getWidth(level), getHeight(level));
775 }
776}
777
778void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
779{
780 // If there currently is a corresponding storage texture image, it has these parameters
781 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
782 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
783 const GLenum storageFormat = getBaseLevelInternalFormat();
784
785 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
786
787 if (mTexStorage)
788 {
789 const int storageLevels = mTexStorage->getLevelCount();
790
791 if ((level >= storageLevels && storageLevels != 0) ||
792 width != storageWidth ||
793 height != storageHeight ||
794 internalformat != storageFormat) // Discard mismatched storage
795 {
796 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
797 {
798 mImageArray[i]->markDirty();
799 }
800
801 SafeDelete(mTexStorage);
802 mDirtyImages = true;
803 }
804 }
805}
806
807void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
808{
809 if (isValidLevel(level))
810 {
811 rx::ImageD3D *image = mImageArray[level];
812 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
813 {
814 image->markClean();
815 }
816 }
817}
818
Brandon Jones0511e802014-07-14 16:27:26 -0700819
820TextureD3D_Cube::TextureD3D_Cube(rx::Renderer *renderer)
821 : TextureCubeImpl(),
822 TextureD3D(renderer),
823 mTexStorage(NULL)
824{
825 for (int i = 0; i < 6; i++)
826 {
827 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
828 {
829 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
830 }
831 }
832}
833
834TextureD3D_Cube::~TextureD3D_Cube()
835{
836 SafeDelete(mTexStorage);
837
838 for (int i = 0; i < 6; i++)
839 {
840 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
841 {
842 SafeDelete(mImageArray[i][j]);
843 }
844 }
845}
846
847TextureD3D_Cube *TextureD3D_Cube::makeTextureD3D_Cube(TextureCubeImpl *texture)
848{
849 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_Cube*, texture));
850 return static_cast<TextureD3D_Cube*>(texture);
851}
852
853TextureStorageInterface *TextureD3D_Cube::getNativeTexture()
854{
855 // ensure the underlying texture is created
856 initializeStorage(false);
857
858 rx::TextureStorageInterface *storage = getBaseLevelStorage();
859 if (storage)
860 {
861 updateStorage();
862 }
863
864 return storage;
865}
866
867Image *TextureD3D_Cube::getImage(GLenum target, int level) const
868{
869 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
870 return mImageArray[targetToIndex(target)][level];
871}
872
873void TextureD3D_Cube::setUsage(GLenum usage)
874{
875 mUsage = usage;
876}
877
878void TextureD3D_Cube::resetDirty()
879{
880 mDirtyImages = false;
881}
882
883GLenum TextureD3D_Cube::getInternalFormat(GLenum target, GLint level) const
884{
885 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
886 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
887 else
888 return GL_NONE;
889}
890
891bool TextureD3D_Cube::isDepth(GLenum target, GLint level) const
892{
893 return gl::GetDepthBits(getInternalFormat(target, level)) > 0;
894}
895
896void TextureD3D_Cube::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
897{
898 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
899 : gl::GetSizedInternalFormat(format, type);
900
901 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
902
903 TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
904}
905
906void TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
907{
908 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
909 int faceIndex = targetToIndex(target);
910 redefineImage(faceIndex, level, format, width, height);
911
912 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
913}
914
915void 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)
916{
917 int faceIndex = targetToIndex(target);
918 if (TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
919 {
920 commitRect(faceIndex, level, xoffset, yoffset, width, height);
921 }
922}
923
924void TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
925{
926 int faceIndex = targetToIndex(target);
927 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
928 {
929 commitRect(faceIndex, level, xoffset, yoffset, width, height);
930 }
931}
932
933void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
934{
935 int faceIndex = targetToIndex(target);
936 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(format) ? format
937 : gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
938 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
939
940 if (!mImageArray[faceIndex][level]->isRenderableFormat())
941 {
942 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
943 mDirtyImages = true;
944 }
945 else
946 {
947 ensureRenderTarget();
948 mImageArray[faceIndex][level]->markClean();
949
950 ASSERT(width == height);
951
952 if (width > 0 && isValidFaceLevel(faceIndex, level))
953 {
954 gl::Rectangle sourceRect;
955 sourceRect.x = x;
956 sourceRect.width = width;
957 sourceRect.y = y;
958 sourceRect.height = height;
959
960 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
961 }
962 }
963}
964
965void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
966{
967 int faceIndex = targetToIndex(target);
968
969 // We can only make our texture storage to a render target if the level we're copying *to* is complete
970 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
971 // rely on the "getBaseLevel*" methods reliably otherwise.
972 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
973
974 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
975 {
976 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
977 mDirtyImages = true;
978 }
979 else
980 {
981 ensureRenderTarget();
982
983 if (isValidFaceLevel(faceIndex, level))
984 {
985 updateStorageFaceLevel(faceIndex, level);
986
987 gl::Rectangle sourceRect;
988 sourceRect.x = x;
989 sourceRect.width = width;
990 sourceRect.y = y;
991 sourceRect.height = height;
992
993 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
994 xoffset, yoffset, mTexStorage, target, level);
995 }
996 }
997}
998
999void TextureD3D_Cube::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1000{
1001 for (int level = 0; level < levels; level++)
1002 {
1003 GLsizei mipSize = std::max(1, size >> level);
1004 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1005 {
1006 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1007 }
1008 }
1009
1010 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1011 {
1012 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1013 {
1014 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1015 }
1016 }
1017
1018 mImmutable = true;
1019
1020 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
1021}
1022
1023bool TextureD3D_Cube::isSamplerComplete(const gl::SamplerState &samplerState) const
1024{
1025 int size = getBaseLevelWidth();
1026
1027 bool mipmapping = IsMipmapFiltered(samplerState);
1028
1029 // TODO(geofflang): use context's texture caps
1030 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
1031 {
1032 if (samplerState.magFilter != GL_NEAREST ||
1033 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
1034 {
1035 return false;
1036 }
1037 }
1038
1039 // TODO(geofflang): use context's extensions
1040 if (!gl::isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT)
1041 {
1042 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
1043 {
1044 return false;
1045 }
1046 }
1047
1048 if (!mipmapping)
1049 {
1050 if (!isCubeComplete())
1051 {
1052 return false;
1053 }
1054 }
1055 else
1056 {
1057 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1058 {
1059 return false;
1060 }
1061 }
1062
1063 return true;
1064}
1065
1066// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1067bool TextureD3D_Cube::isCubeComplete() const
1068{
1069 int baseWidth = getBaseLevelWidth();
1070 int baseHeight = getBaseLevelHeight();
1071 GLenum baseFormat = getBaseLevelInternalFormat();
1072
1073 if (baseWidth <= 0 || baseWidth != baseHeight)
1074 {
1075 return false;
1076 }
1077
1078 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1079 {
1080 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1081
1082 if (faceBaseImage.getWidth() != baseWidth ||
1083 faceBaseImage.getHeight() != baseHeight ||
1084 faceBaseImage.getInternalFormat() != baseFormat )
1085 {
1086 return false;
1087 }
1088 }
1089
1090 return true;
1091}
1092
1093void TextureD3D_Cube::generateMipmaps()
1094{
1095 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1096 int levelCount = mipLevels();
1097 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1098 {
1099 for (int level = 1; level < levelCount; level++)
1100 {
1101 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1102 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1103 }
1104 }
1105
1106 if (mTexStorage && mTexStorage->isRenderTarget())
1107 {
1108 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1109 {
1110 for (int level = 1; level < levelCount; level++)
1111 {
1112 mTexStorage->generateMipmap(faceIndex, level);
1113
1114 mImageArray[faceIndex][level]->markClean();
1115 }
1116 }
1117 }
1118 else
1119 {
1120 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1121 {
1122 for (int level = 1; level < levelCount; level++)
1123 {
1124 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
1125 }
1126 }
1127 }
1128}
1129
1130unsigned int TextureD3D_Cube::getRenderTargetSerial(GLenum target, GLint level)
1131{
1132 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
1133}
1134
1135RenderTarget *TextureD3D_Cube::getRenderTarget(GLenum target, GLint level)
1136{
1137 ASSERT(gl::IsCubemapTextureTarget(target));
1138
1139 // ensure the underlying texture is created
1140 if (!ensureRenderTarget())
1141 {
1142 return NULL;
1143 }
1144
1145 updateStorageFaceLevel(targetToIndex(target), level);
1146
1147 // ensure this is NOT a depth texture
1148 if (isDepth(target, level))
1149 {
1150 return NULL;
1151 }
1152
1153 return mTexStorage->getRenderTarget(target, level);
1154}
1155
1156RenderTarget *TextureD3D_Cube::getDepthStencil(GLenum target, GLint level)
1157{
1158 ASSERT(gl::IsCubemapTextureTarget(target));
1159
1160 // ensure the underlying texture is created
1161 if (!ensureRenderTarget())
1162 {
1163 return NULL;
1164 }
1165
1166 updateStorageFaceLevel(targetToIndex(target), level);
1167
1168 // ensure this is a depth texture
1169 if (!isDepth(target, level))
1170 {
1171 return NULL;
1172 }
1173
1174 return mTexStorage->getRenderTarget(target, level);
1175}
1176
1177int TextureD3D_Cube::targetToIndex(GLenum target)
1178{
1179 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1180 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1181 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1182 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1183 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1184
1185 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
1186}
1187
1188void TextureD3D_Cube::initializeStorage(bool renderTarget)
1189{
1190 // Only initialize the first time this texture is used as a render target or shader resource
1191 if (mTexStorage)
1192 {
1193 return;
1194 }
1195
1196 // do not attempt to create storage for nonexistant data
1197 if (!isFaceLevelComplete(0, 0))
1198 {
1199 return;
1200 }
1201
1202 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1203
1204 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1205 ASSERT(mTexStorage);
1206
1207 // flush image data to the storage
1208 updateStorage();
1209}
1210
1211TextureStorageInterfaceCube *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
1212{
1213 GLsizei size = getBaseLevelWidth();
1214
1215 ASSERT(size > 0);
1216
1217 // use existing storage level count, when previously specified by TexStorage*D
1218 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1219
1220 return new TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
1221}
1222
1223void TextureD3D_Cube::setCompleteTexStorage(TextureStorageInterfaceCube *newCompleteTexStorage)
1224{
1225 SafeDelete(mTexStorage);
1226 mTexStorage = newCompleteTexStorage;
1227
1228 if (mTexStorage && mTexStorage->isManaged())
1229 {
1230 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1231 {
1232 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1233 {
1234 mImageArray[faceIndex][level]->setManagedSurface(mTexStorage, faceIndex, level);
1235 }
1236 }
1237 }
1238
1239 mDirtyImages = true;
1240}
1241
1242void TextureD3D_Cube::updateStorage()
1243{
1244 ASSERT(mTexStorage != NULL);
1245 GLint storageLevels = mTexStorage->getLevelCount();
1246 for (int face = 0; face < 6; face++)
1247 {
1248 for (int level = 0; level < storageLevels; level++)
1249 {
1250 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1251 {
1252 updateStorageFaceLevel(face, level);
1253 }
1254 }
1255 }
1256}
1257
1258bool TextureD3D_Cube::ensureRenderTarget()
1259{
1260 initializeStorage(true);
1261
1262 if (getBaseLevelWidth() > 0)
1263 {
1264 ASSERT(mTexStorage);
1265 if (!mTexStorage->isRenderTarget())
1266 {
1267 TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1268
1269 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
1270 {
1271 delete newRenderTargetStorage;
1272 return gl::error(GL_OUT_OF_MEMORY, false);
1273 }
1274
1275 setCompleteTexStorage(newRenderTargetStorage);
1276 }
1277 }
1278
1279 return (mTexStorage && mTexStorage->isRenderTarget());
1280}
1281
1282TextureStorageInterface *TextureD3D_Cube::getBaseLevelStorage()
1283{
1284 return mTexStorage;
1285}
1286
1287const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1288{
1289 // Note: if we are not cube-complete, there is no single base level image that can describe all
1290 // cube faces, so this method is only well-defined for a cube-complete base level.
1291 return mImageArray[0][0];
1292}
1293
1294bool TextureD3D_Cube::isMipmapCubeComplete() const
1295{
1296 if (isImmutable())
1297 {
1298 return true;
1299 }
1300
1301 if (!isCubeComplete())
1302 {
1303 return false;
1304 }
1305
1306 int levelCount = mipLevels();
1307
1308 for (int face = 0; face < 6; face++)
1309 {
1310 for (int level = 1; level < levelCount; level++)
1311 {
1312 if (!isFaceLevelComplete(face, level))
1313 {
1314 return false;
1315 }
1316 }
1317 }
1318
1319 return true;
1320}
1321
1322bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1323{
1324 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1325}
1326
1327
1328bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1329{
1330 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1331
1332 if (isImmutable())
1333 {
1334 return true;
1335 }
1336
1337 int baseSize = getBaseLevelWidth();
1338
1339 if (baseSize <= 0)
1340 {
1341 return false;
1342 }
1343
1344 // "isCubeComplete" checks for base level completeness and we must call that
1345 // to determine if any face at level 0 is complete. We omit that check here
1346 // to avoid re-checking cube-completeness for every face at level 0.
1347 if (level == 0)
1348 {
1349 return true;
1350 }
1351
1352 // Check that non-zero levels are consistent with the base level.
1353 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1354
1355 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1356 {
1357 return false;
1358 }
1359
1360 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1361 {
1362 return false;
1363 }
1364
1365 return true;
1366}
1367
1368void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1369{
1370 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1371 ImageD3D *image = mImageArray[faceIndex][level];
1372
1373 if (image->isDirty())
1374 {
1375 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1376 }
1377}
1378
1379void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1380{
1381 // If there currently is a corresponding storage texture image, it has these parameters
1382 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1383 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1384 const GLenum storageFormat = getBaseLevelInternalFormat();
1385
1386 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1387
1388 if (mTexStorage)
1389 {
1390 const int storageLevels = mTexStorage->getLevelCount();
1391
1392 if ((level >= storageLevels && storageLevels != 0) ||
1393 width != storageWidth ||
1394 height != storageHeight ||
1395 internalformat != storageFormat) // Discard mismatched storage
1396 {
1397 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1398 {
1399 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1400 {
1401 mImageArray[faceIndex][level]->markDirty();
1402 }
1403 }
1404
1405 SafeDelete(mTexStorage);
1406
1407 mDirtyImages = true;
1408 }
1409 }
1410}
1411
1412void TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
1413{
1414 if (isValidFaceLevel(faceIndex, level))
1415 {
1416 ImageD3D *image = mImageArray[faceIndex][level];
1417 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
1418 image->markClean();
1419 }
1420}
1421
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001422}