blob: e105df66b45e8e29bb6e481f727d72a766ab827f [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"
11#include "libEGL/Surface.h"
12#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
14#include "libGLESv2/main.h"
15#include "libGLESv2/formatutils.h"
16#include "libGLESv2/renderer/BufferImpl.h"
17#include "libGLESv2/renderer/RenderTarget.h"
18#include "libGLESv2/renderer/Renderer.h"
19#include "libGLESv2/renderer/d3d/ImageD3D.h"
20#include "libGLESv2/renderer/d3d/TextureD3D.h"
21#include "libGLESv2/renderer/d3d/TextureStorage.h"
22
23namespace rx
24{
25
26bool IsMipmapFiltered(const gl::SamplerState &samplerState)
27{
28 switch (samplerState.minFilter)
29 {
30 case GL_NEAREST:
31 case GL_LINEAR:
32 return false;
33 case GL_NEAREST_MIPMAP_NEAREST:
34 case GL_LINEAR_MIPMAP_NEAREST:
35 case GL_NEAREST_MIPMAP_LINEAR:
36 case GL_LINEAR_MIPMAP_LINEAR:
37 return true;
38 default: UNREACHABLE();
39 return false;
40 }
41}
42
43bool IsRenderTargetUsage(GLenum usage)
44{
45 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
46}
47
48TextureD3D::TextureD3D(rx::Renderer *renderer)
49 : mRenderer(renderer),
50 mUsage(GL_NONE),
51 mDirtyImages(true),
52 mImmutable(false)
53{
54}
55
56TextureD3D::~TextureD3D()
57{
58}
59
60GLint TextureD3D::getBaseLevelWidth() const
61{
62 const rx::Image *baseImage = getBaseLevelImage();
63 return (baseImage ? baseImage->getWidth() : 0);
64}
65
66GLint TextureD3D::getBaseLevelHeight() const
67{
68 const rx::Image *baseImage = getBaseLevelImage();
69 return (baseImage ? baseImage->getHeight() : 0);
70}
71
72GLint TextureD3D::getBaseLevelDepth() const
73{
74 const rx::Image *baseImage = getBaseLevelImage();
75 return (baseImage ? baseImage->getDepth() : 0);
76}
77
78// Note: "base level image" is loosely defined to be any image from the base level,
79// where in the base of 2D array textures and cube maps there are several. Don't use
80// the base level image for anything except querying texture format and size.
81GLenum TextureD3D::getBaseLevelInternalFormat() const
82{
83 const rx::Image *baseImage = getBaseLevelImage();
84 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
85}
86
87void TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
88{
89 // No-op
90 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
91 {
92 return;
93 }
94
95 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
96 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
97 const void *pixelData = pixels;
98
99 if (unpack.pixelBuffer.id() != 0)
100 {
101 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
102 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
103 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
104 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
105 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
106 const void *bufferData = pixelBuffer->getImplementation()->getData();
107 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
108 }
109
110 if (pixelData != NULL)
111 {
112 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
113 mDirtyImages = true;
114 }
115}
116
117bool TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
118 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, rx::Image *image)
119{
120 const void *pixelData = pixels;
121
122 // CPU readback & copy where direct GPU copy is not supported
123 if (unpack.pixelBuffer.id() != 0)
124 {
125 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
126 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
127 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
128 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
129 const void *bufferData = pixelBuffer->getImplementation()->getData();
130 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
131 }
132
133 if (pixelData != NULL)
134 {
135 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
136 mDirtyImages = true;
137 }
138
139 return true;
140}
141
142void TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
143{
144 if (pixels != NULL)
145 {
146 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
147 mDirtyImages = true;
148 }
149}
150
151bool TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
152 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
153{
154 if (pixels != NULL)
155 {
156 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
157 mDirtyImages = true;
158 }
159
160 return true;
161}
162
163bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
164{
165 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
166}
167
168bool TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
169 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
170{
171 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
172 {
173 return true;
174 }
175
176 // In order to perform the fast copy through the shader, we must have the right format, and be able
177 // to create a render target.
178 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
179
180 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
181
182 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
183}
184
185GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
186{
187 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
188 {
189 // Maximum number of levels
190 return gl::log2(std::max(std::max(width, height), depth)) + 1;
191 }
192 else
193 {
194 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
195 return 1;
196 }
197}
198
199int TextureD3D::mipLevels() const
200{
201 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
202}
203
204
205TextureD3D_2D::TextureD3D_2D(rx::Renderer *renderer)
206 : TextureD3D(renderer),
207 Texture2DImpl(),
208 mTexStorage(NULL)
209{
210 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
211 {
212 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
213 }
214}
215
216TextureD3D_2D::~TextureD3D_2D()
217{
218 SafeDelete(mTexStorage);
219
220 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
221 {
222 delete mImageArray[i];
223 }
224}
225
226TextureD3D_2D *TextureD3D_2D::makeTextureD3D_2D(Texture2DImpl *texture)
227{
228 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D_2D*, texture));
229 return static_cast<TextureD3D_2D*>(texture);
230}
231
232TextureStorageInterface *TextureD3D_2D::getNativeTexture()
233{
234 // ensure the underlying texture is created
235 initializeStorage(false);
236
237 rx::TextureStorageInterface *storage = getBaseLevelStorage();
238 if (storage)
239 {
240 updateStorage();
241 }
242
243 return storage;
244}
245
246Image *TextureD3D_2D::getImage(int level) const
247{
248 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
249 return mImageArray[level];
250}
251
252void TextureD3D_2D::setUsage(GLenum usage)
253{
254 mUsage = usage;
255}
256
257void TextureD3D_2D::resetDirty()
258{
259 mDirtyImages = false;
260}
261
262GLsizei TextureD3D_2D::getWidth(GLint level) const
263{
264 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
265 return mImageArray[level]->getWidth();
266 else
267 return 0;
268}
269
270GLsizei TextureD3D_2D::getHeight(GLint level) const
271{
272 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
273 return mImageArray[level]->getHeight();
274 else
275 return 0;
276}
277
278GLenum TextureD3D_2D::getInternalFormat(GLint level) const
279{
280 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
281 return mImageArray[level]->getInternalFormat();
282 else
283 return GL_NONE;
284}
285
286GLenum TextureD3D_2D::getActualFormat(GLint level) const
287{
288 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
289 return mImageArray[level]->getActualFormat();
290 else
291 return GL_NONE;
292}
293
294bool TextureD3D_2D::isDepth(GLint level) const
295{
296 return gl::GetDepthBits(getInternalFormat(level)) > 0;
297}
298
299void TextureD3D_2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
300{
301 GLenum sizedInternalFormat = gl::IsSizedInternalFormat(internalFormat) ? internalFormat
302 : gl::GetSizedInternalFormat(format, type);
303 bool fastUnpacked = false;
304
305 // Attempt a fast gpu copy of the pixel data to the surface
306 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
307 {
308 // Will try to create RT storage if it does not exist
309 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
310 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
311
312 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
313 {
314 // Ensure we don't overwrite our newly initialized data
315 mImageArray[level]->markClean();
316
317 fastUnpacked = true;
318 }
319 }
320
321 if (!fastUnpacked)
322 {
323 TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
324 }
325}
326
327void TextureD3D_2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
328{
329 TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
330}
331
332void TextureD3D_2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels)
333{
334 bool fastUnpacked = false;
335
336 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
337 {
338 rx::RenderTarget *renderTarget = getRenderTarget(level);
339 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
340
341 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
342 {
343 // Ensure we don't overwrite our newly initialized data
344 mImageArray[level]->markClean();
345
346 fastUnpacked = true;
347 }
348 }
349
350 if (!fastUnpacked && TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
351 {
352 commitRect(level, xoffset, yoffset, width, height);
353 }
354}
355
356void TextureD3D_2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
357{
358 if (TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
359 {
360 commitRect(level, xoffset, yoffset, width, height);
361 }
362}
363
364void TextureD3D_2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
365{
366 if (!mImageArray[level]->isRenderableFormat())
367 {
368 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
369 mDirtyImages = true;
370 }
371 else
372 {
373 ensureRenderTarget();
374 mImageArray[level]->markClean();
375
376 if (width != 0 && height != 0 && isValidLevel(level))
377 {
378 gl::Rectangle sourceRect;
379 sourceRect.x = x;
380 sourceRect.width = width;
381 sourceRect.y = y;
382 sourceRect.height = height;
383
384 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
385 }
386 }
387}
388
389void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
390{
391 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
392 // the current level we're copying to is defined (with appropriate format, width & height)
393 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
394
395 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
396 {
397 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
398 mDirtyImages = true;
399 }
400 else
401 {
402 ensureRenderTarget();
403
404 if (isValidLevel(level))
405 {
406 updateStorageLevel(level);
407
408 gl::Rectangle sourceRect;
409 sourceRect.x = x;
410 sourceRect.width = width;
411 sourceRect.y = y;
412 sourceRect.height = height;
413
414 mRenderer->copyImage(source, sourceRect,
415 gl::GetFormat(getBaseLevelInternalFormat()),
416 xoffset, yoffset, mTexStorage, level);
417 }
418 }
419}
420
421void TextureD3D_2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
422{
423 for (int level = 0; level < levels; level++)
424 {
425 GLsizei levelWidth = std::max(1, width >> level);
426 GLsizei levelHeight = std::max(1, height >> level);
427 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
428 }
429
430 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
431 {
432 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
433 }
434
435 mImmutable = true;
436
437 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
438}
439
440// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
441bool TextureD3D_2D::isSamplerComplete(const gl::SamplerState &samplerState) const
442{
443 GLsizei width = getBaseLevelWidth();
444 GLsizei height = getBaseLevelHeight();
445
446 if (width <= 0 || height <= 0)
447 {
448 return false;
449 }
450
451 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
452 {
453 if (samplerState.magFilter != GL_NEAREST ||
454 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
455 {
456 return false;
457 }
458 }
459
460 // TODO(geofflang): use context's extensions
461 bool npotSupport = mRenderer->getRendererExtensions().textureNPOT;
462
463 if (!npotSupport)
464 {
465 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !gl::isPow2(width)) ||
466 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !gl::isPow2(height)))
467 {
468 return false;
469 }
470 }
471
472 if (IsMipmapFiltered(samplerState))
473 {
474 if (!npotSupport)
475 {
476 if (!gl::isPow2(width) || !gl::isPow2(height))
477 {
478 return false;
479 }
480 }
481
482 if (!isMipmapComplete())
483 {
484 return false;
485 }
486 }
487
488 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
489 // The internalformat specified for the texture arrays is a sized internal depth or
490 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
491 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
492 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
493 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
494 {
495 if (samplerState.compareMode == GL_NONE)
496 {
497 if ((samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
498 samplerState.magFilter != GL_NEAREST)
499 {
500 return false;
501 }
502 }
503 }
504
505 return true;
506}
507
508void TextureD3D_2D::bindTexImage(egl::Surface *surface)
509{
510 GLenum internalformat = surface->getFormat();
511
512 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
513
514 if (mTexStorage)
515 {
516 SafeDelete(mTexStorage);
517 }
518 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
519
520 mDirtyImages = true;
521}
522
523void TextureD3D_2D::releaseTexImage()
524{
525 if (mTexStorage)
526 {
527 SafeDelete(mTexStorage);
528 }
529
530 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
531 {
532 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
533 }
534}
535
536void TextureD3D_2D::generateMipmaps()
537{
538 int levelCount = mipLevels();
539
540 if (mTexStorage && mTexStorage->isRenderTarget())
541 {
542 for (int level = 1; level < levelCount; level++)
543 {
544 mTexStorage->generateMipmap(level);
545
546 mImageArray[level]->markClean();
547 }
548 }
549 else
550 {
551 for (int level = 1; level < levelCount; level++)
552 {
553 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
554 }
555 }
556}
557
558unsigned int TextureD3D_2D::getRenderTargetSerial(GLint level)
559{
560 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
561}
562
563RenderTarget *TextureD3D_2D::getRenderTarget(GLint level)
564{
565 // ensure the underlying texture is created
566 if (!ensureRenderTarget())
567 {
568 return NULL;
569 }
570
571 updateStorageLevel(level);
572
573 // ensure this is NOT a depth texture
574 if (isDepth(level))
575 {
576 return NULL;
577 }
578
579 return mTexStorage->getRenderTarget(level);
580}
581
582RenderTarget *TextureD3D_2D::getDepthSencil(GLint level)
583{
584 // ensure the underlying texture is created
585 if (!ensureRenderTarget())
586 {
587 return NULL;
588 }
589
590 updateStorageLevel(level);
591
592 // ensure this is actually a depth texture
593 if (!isDepth(level))
594 {
595 return NULL;
596 }
597
598 return mTexStorage->getRenderTarget(level);
599}
600
601// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
602bool TextureD3D_2D::isMipmapComplete() const
603{
604 int levelCount = mipLevels();
605
606 for (int level = 0; level < levelCount; level++)
607 {
608 if (!isLevelComplete(level))
609 {
610 return false;
611 }
612 }
613
614 return true;
615}
616
617bool TextureD3D_2D::isValidLevel(int level) const
618{
619 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
620}
621
622bool TextureD3D_2D::isLevelComplete(int level) const
623{
624 if (isImmutable())
625 {
626 return true;
627 }
628
629 const rx::Image *baseImage = getBaseLevelImage();
630
631 GLsizei width = baseImage->getWidth();
632 GLsizei height = baseImage->getHeight();
633
634 if (width <= 0 || height <= 0)
635 {
636 return false;
637 }
638
639 // The base image level is complete if the width and height are positive
640 if (level == 0)
641 {
642 return true;
643 }
644
645 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
646 rx::Image *image = mImageArray[level];
647
648 if (image->getInternalFormat() != baseImage->getInternalFormat())
649 {
650 return false;
651 }
652
653 if (image->getWidth() != std::max(1, width >> level))
654 {
655 return false;
656 }
657
658 if (image->getHeight() != std::max(1, height >> level))
659 {
660 return false;
661 }
662
663 return true;
664}
665
666// Constructs a native texture resource from the texture images
667void TextureD3D_2D::initializeStorage(bool renderTarget)
668{
669 // Only initialize the first time this texture is used as a render target or shader resource
670 if (mTexStorage)
671 {
672 return;
673 }
674
675 // do not attempt to create storage for nonexistant data
676 if (!isLevelComplete(0))
677 {
678 return;
679 }
680
681 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
682
683 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
684 ASSERT(mTexStorage);
685
686 // flush image data to the storage
687 updateStorage();
688}
689
690rx::TextureStorageInterface2D *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
691{
692 GLsizei width = getBaseLevelWidth();
693 GLsizei height = getBaseLevelHeight();
694
695 ASSERT(width > 0 && height > 0);
696
697 // use existing storage level count, when previously specified by TexStorage*D
698 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
699
700 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
701}
702
703void TextureD3D_2D::setCompleteTexStorage(TextureStorageInterface2D *newCompleteTexStorage)
704{
705 SafeDelete(mTexStorage);
706 mTexStorage = newCompleteTexStorage;
707
708 if (mTexStorage && mTexStorage->isManaged())
709 {
710 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
711 {
712 mImageArray[level]->setManagedSurface(mTexStorage, level);
713 }
714 }
715
716 mDirtyImages = true;
717}
718
719void TextureD3D_2D::updateStorage()
720{
721 ASSERT(mTexStorage != NULL);
722 GLint storageLevels = mTexStorage->getLevelCount();
723 for (int level = 0; level < storageLevels; level++)
724 {
725 if (mImageArray[level]->isDirty() && isLevelComplete(level))
726 {
727 updateStorageLevel(level);
728 }
729 }
730}
731
732bool TextureD3D_2D::ensureRenderTarget()
733{
734 initializeStorage(true);
735
736 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
737 {
738 ASSERT(mTexStorage);
739 if (!mTexStorage->isRenderTarget())
740 {
741 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
742
743 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
744 {
745 delete newRenderTargetStorage;
746 return gl::error(GL_OUT_OF_MEMORY, false);
747 }
748
749 setCompleteTexStorage(newRenderTargetStorage);
750 }
751 }
752
753 return (mTexStorage && mTexStorage->isRenderTarget());
754}
755
756TextureStorageInterface *TextureD3D_2D::getBaseLevelStorage()
757{
758 return mTexStorage;
759}
760
761const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
762{
763 return mImageArray[0];
764}
765
766void TextureD3D_2D::updateStorageLevel(int level)
767{
768 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
769 ASSERT(isLevelComplete(level));
770
771 if (mImageArray[level]->isDirty())
772 {
773 commitRect(level, 0, 0, getWidth(level), getHeight(level));
774 }
775}
776
777void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
778{
779 // If there currently is a corresponding storage texture image, it has these parameters
780 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
781 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
782 const GLenum storageFormat = getBaseLevelInternalFormat();
783
784 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
785
786 if (mTexStorage)
787 {
788 const int storageLevels = mTexStorage->getLevelCount();
789
790 if ((level >= storageLevels && storageLevels != 0) ||
791 width != storageWidth ||
792 height != storageHeight ||
793 internalformat != storageFormat) // Discard mismatched storage
794 {
795 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
796 {
797 mImageArray[i]->markDirty();
798 }
799
800 SafeDelete(mTexStorage);
801 mDirtyImages = true;
802 }
803 }
804}
805
806void TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
807{
808 if (isValidLevel(level))
809 {
810 rx::ImageD3D *image = mImageArray[level];
811 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
812 {
813 image->markClean();
814 }
815 }
816}
817
818}