blob: 3847fa20be86b3ee05affe5ec091bb52d2ea4fc4 [file] [log] [blame]
shannon.woods@transgaming.combdf2d802013-02-28 23:16:20 +00001#include "precompiled.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002//
Geoff Langcec35902014-04-16 10:52:36 -04003// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00004// Use of this source code is governed by a BSD-style license that can be
5// found in the LICENSE file.
6//
7
8// Texture.cpp: Implements the gl::Texture class and its derived classes
9// Texture2D and TextureCubeMap. Implements GL texture objects and related
10// functionality. [OpenGL ES 2.0.24] section 3.7 page 63.
11
12#include "libGLESv2/Texture.h"
13
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000014#include "libGLESv2/main.h"
shannonwoods@chromium.orga2ecfcc2013-05-30 00:11:59 +000015#include "common/mathutil.h"
16#include "common/utilities.h"
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +000017#include "libGLESv2/formatutils.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000018#include "libGLESv2/Renderbuffer.h"
19#include "libGLESv2/renderer/Image.h"
20#include "libGLESv2/renderer/Renderer.h"
Brandon Jones6518fe22014-07-08 15:16:52 -070021#include "libGLESv2/renderer/d3d/ImageD3D.h"
22#include "libGLESv2/renderer/d3d/TextureStorage.h"
shannon.woods@transgaming.com486d9e92013-02-28 23:15:41 +000023#include "libEGL/Surface.h"
Jamie Madill1beb1db2013-09-18 14:36:28 -040024#include "libGLESv2/Buffer.h"
Brandon Jonesd38f9262014-06-18 16:26:45 -070025#include "libGLESv2/renderer/BufferImpl.h"
Jamie Madill0e0510f2013-10-10 15:46:23 -040026#include "libGLESv2/renderer/RenderTarget.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070027#include "libGLESv2/renderer/TextureImpl.h"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000028
29namespace gl
30{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000031
Jamie Madillf8989902013-07-19 16:36:58 -040032bool IsMipmapFiltered(const SamplerState &samplerState)
33{
34 switch (samplerState.minFilter)
35 {
36 case GL_NEAREST:
37 case GL_LINEAR:
38 return false;
39 case GL_NEAREST_MIPMAP_NEAREST:
40 case GL_LINEAR_MIPMAP_NEAREST:
41 case GL_NEAREST_MIPMAP_LINEAR:
42 case GL_LINEAR_MIPMAP_LINEAR:
43 return true;
44 default: UNREACHABLE();
45 return false;
46 }
47}
48
Jamie Madilld4589c92013-10-24 17:49:34 -040049bool IsRenderTargetUsage(GLenum usage)
50{
51 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
52}
53
Brandon Jonesf47bebc2014-07-09 14:28:42 -070054Texture::Texture(GLuint id, GLenum target)
55 : RefCountObject(id),
56 mUsage(GL_NONE),
57 mImmutable(false),
58 mTarget(target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000060}
61
62Texture::~Texture()
63{
64}
65
Geoff Lang4907f2c2013-07-25 12:53:57 -040066GLenum Texture::getTarget() const
67{
68 return mTarget;
69}
70
Geoff Lang63b5f1f2013-09-23 14:52:14 -040071void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000072{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040073 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000074}
75
Brandon Jonesa328d562014-07-01 13:52:40 -070076void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler)
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000077{
78 *sampler = mSamplerState;
Nicolas Capens8de68282014-04-04 11:10:27 -040079
80 // Offset the effective base level by the texture storage's top level
81 rx::TextureStorageInterface *texture = getNativeTexture();
82 int topLevel = texture ? texture->getTopLevel() : 0;
83 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +000084}
85
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000086GLenum Texture::getUsage() const
87{
88 return mUsage;
89}
90
Jamie Madilld3d2a342013-10-07 10:46:35 -040091GLint Texture::getBaseLevelWidth() const
92{
93 const rx::Image *baseImage = getBaseLevelImage();
94 return (baseImage ? baseImage->getWidth() : 0);
95}
96
97GLint Texture::getBaseLevelHeight() const
98{
99 const rx::Image *baseImage = getBaseLevelImage();
100 return (baseImage ? baseImage->getHeight() : 0);
101}
102
103GLint Texture::getBaseLevelDepth() const
104{
105 const rx::Image *baseImage = getBaseLevelImage();
106 return (baseImage ? baseImage->getDepth() : 0);
107}
108
Jamie Madillb8f8b892014-01-07 10:12:50 -0500109// Note: "base level image" is loosely defined to be any image from the base level,
110// where in the base of 2D array textures and cube maps there are several. Don't use
111// the base level image for anything except querying texture format and size.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400112GLenum Texture::getBaseLevelInternalFormat() const
113{
114 const rx::Image *baseImage = getBaseLevelImage();
115 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
116}
117
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700118unsigned int Texture::getTextureSerial()
119{
120 rx::TextureStorageInterface *texture = getNativeTexture();
121 return texture ? texture->getTextureSerial() : 0;
122}
123
124bool Texture::isImmutable() const
125{
126 return mImmutable;
127}
128
129int Texture::immutableLevelCount()
130{
131 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
132}
133
134int Texture::mipLevels() const
135{
136 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
137}
138
139TextureWithRenderer::TextureWithRenderer(rx::Renderer *renderer, GLuint id, GLenum target)
140 : Texture(id, target),
141 mRenderer(renderer),
142 mDirtyImages(true)
143{
144}
145
146TextureWithRenderer::~TextureWithRenderer()
147{
148}
149
150// TODO: This is only used by the D3D backends and FramebufferAttachment. Once
151// FramebufferAttachment has been refactored this function should be pushed
152// down to TextureD3D.
153rx::TextureStorageInterface *TextureWithRenderer::getNativeTexture()
154{
155 // ensure the underlying texture is created
156 initializeStorage(false);
157
158 rx::TextureStorageInterface *storage = getBaseLevelStorage();
159 if (storage)
160 {
161 updateStorage();
162 }
163
164 return storage;
165}
166
167bool TextureWithRenderer::hasDirtyImages() const
168{
169 return mDirtyImages;
170}
171
172void TextureWithRenderer::resetDirty()
173{
174 mDirtyImages = false;
175}
176
177void TextureWithRenderer::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000178{
Jamie Madillc30003d2014-01-10 12:51:23 -0500179 // No-op
180 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
181 {
182 return;
183 }
184
Jamie Madillabef6802013-09-05 16:54:19 -0400185 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
186 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill1beb1db2013-09-18 14:36:28 -0400187 const void *pixelData = pixels;
188
189 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000190 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400191 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
192 Buffer *pixelBuffer = unpack.pixelBuffer.get();
193 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700194 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
195 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
196 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill1beb1db2013-09-18 14:36:28 -0400197 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
198 }
199
200 if (pixelData != NULL)
201 {
202 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000203 mDirtyImages = true;
204 }
205}
206
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700207bool TextureWithRenderer::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400208{
209 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
210}
211
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700212bool TextureWithRenderer::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400213 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400214{
215 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
216 {
217 return true;
218 }
219
220 // In order to perform the fast copy through the shader, we must have the right format, and be able
221 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400222 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400223
Jamie Madill8cc7d972013-10-10 15:51:55 -0400224 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400225
Jamie Madill8cc7d972013-10-10 15:51:55 -0400226 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400227}
228
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700229void TextureWithRenderer::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000230{
231 if (pixels != NULL)
232 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000233 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000234 mDirtyImages = true;
235 }
236}
237
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238bool TextureWithRenderer::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400239 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000240{
Jamie Madill065e1a32013-10-10 15:11:50 -0400241 const void *pixelData = pixels;
242
243 // CPU readback & copy where direct GPU copy is not supported
244 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000245 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400246 Buffer *pixelBuffer = unpack.pixelBuffer.get();
247 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700248 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
249 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
250 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill065e1a32013-10-10 15:11:50 -0400251 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
252 }
253
254 if (pixelData != NULL)
255 {
256 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000257 mDirtyImages = true;
258 }
259
260 return true;
261}
262
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700263bool TextureWithRenderer::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000264 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000265{
266 if (pixels != NULL)
267 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000268 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000269 mDirtyImages = true;
270 }
271
272 return true;
273}
274
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700275GLint TextureWithRenderer::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000276{
Geoff Langc0b9ef42014-07-02 10:02:37 -0400277 // TODO(geofflang): use context's extensions
278 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000279 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400280 // Maximum number of levels
Geoff Lang98705b72014-03-31 16:00:03 -0400281 return log2(std::max(std::max(width, height), depth)) + 1;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000282 }
283 else
284 {
285 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
286 return 1;
287 }
288}
289
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700290Texture2D::Texture2D(rx::Texture2DImpl *impl, GLuint id)
291 : Texture(id, GL_TEXTURE_2D),
292 mTexture(impl)
Jamie Madill22f843a2013-10-24 17:49:36 -0400293{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000294 mSurface = NULL;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000295}
296
297Texture2D::~Texture2D()
298{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700299 SafeDelete(mTexture);
300
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000301 if (mSurface)
302 {
303 mSurface->setBoundTexture(NULL);
304 mSurface = NULL;
305 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700306}
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000307
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700308rx::TextureStorageInterface *Texture2D::getNativeTexture()
309{
310 return mTexture->getNativeTexture();
311}
312
313void Texture2D::setUsage(GLenum usage)
314{
315 mUsage = usage;
316 mTexture->setUsage(usage);
317}
318
319bool Texture2D::hasDirtyImages() const
320{
321 return mTexture->hasDirtyImages();
322}
323
324void Texture2D::resetDirty()
325{
326 mTexture->resetDirty();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000327}
328
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000329GLsizei Texture2D::getWidth(GLint level) const
330{
331 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700332 return mTexture->getImage(level)->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000333 else
334 return 0;
335}
336
337GLsizei Texture2D::getHeight(GLint level) const
338{
339 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700340 return mTexture->getImage(level)->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000341 else
342 return 0;
343}
344
345GLenum Texture2D::getInternalFormat(GLint level) const
346{
347 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700348 return mTexture->getImage(level)->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000349 else
350 return GL_NONE;
351}
352
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000353GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000354{
355 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700356 return mTexture->getImage(level)->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000357 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500358 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000359}
360
Geoff Lang005df412013-10-16 14:12:50 -0400361void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000362{
363 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000364
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700365 mTexture->redefineImage(level, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000366}
367
Geoff Lang005df412013-10-16 14:12:50 -0400368void Texture2D::setImage(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369{
Geoff Lange4a492b2014-06-19 14:14:41 -0400370 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
371 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000372 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000373
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700374 mTexture->setImage(level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000375}
376
377void Texture2D::bindTexImage(egl::Surface *surface)
378{
379 releaseTexImage();
380
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700381 mTexture->bindTexImage(surface);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000382
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000383 mSurface = surface;
384 mSurface->setBoundTexture(this);
385}
386
387void Texture2D::releaseTexImage()
388{
389 if (mSurface)
390 {
391 mSurface->setBoundTexture(NULL);
392 mSurface = NULL;
393
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700394 mTexture->releaseTexImage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000395 }
396}
397
398void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
399{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000400 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000401 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000402
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700403 mTexture->setCompressedImage(level, format, width, height, imageSize, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000404}
405
Jamie Madill88f18f42013-09-18 14:36:19 -0400406void Texture2D::subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700408 mTexture->subImage(level, xoffset, yoffset, width, height, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000409}
410
411void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
412{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700413 mTexture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000414}
415
416void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
417{
Geoff Lange4a492b2014-06-19 14:14:41 -0400418 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
419 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000420 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000421
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700422 mTexture->copyImage(level, format, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000423}
424
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000425void Texture2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000426{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700427 mTexture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000428}
429
430void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
431{
Jamie Madill73b5d062013-10-24 17:49:38 -0400432 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000433
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700434 mTexture->storage(levels, internalformat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000435}
436
437// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400438bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000439{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700440 return mTexture->isSamplerComplete(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000441}
442
443bool Texture2D::isCompressed(GLint level) const
444{
Geoff Lange4a492b2014-06-19 14:14:41 -0400445 return IsFormatCompressed(getInternalFormat(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000446}
447
448bool Texture2D::isDepth(GLint level) const
449{
Geoff Lange4a492b2014-06-19 14:14:41 -0400450 return GetDepthBits(getInternalFormat(level)) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000451}
452
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453void Texture2D::generateMipmaps()
454{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000455 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400456 int levelCount = mipLevels();
457 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000458 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400459 redefineImage(level, getBaseLevelInternalFormat(),
460 std::max(getBaseLevelWidth() >> level, 1),
461 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000462 }
463
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700464 mTexture->generateMipmaps();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000465}
466
Jamie Madilld3d2a342013-10-07 10:46:35 -0400467const rx::Image *Texture2D::getBaseLevelImage() const
468{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700469 return mTexture->getImage(0);
Jamie Madill2ebab852013-10-24 17:49:42 -0400470}
471
Geoff Lang8040f572013-07-25 16:49:54 -0400472unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000473{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700474 return mTexture->getRenderTargetSerial(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400475}
476
477rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
478{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700479 return mTexture->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000480}
481
Geoff Lang8040f572013-07-25 16:49:54 -0400482rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000483{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700484 return mTexture->getDepthSencil(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485}
486
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700487TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id)
488 : TextureWithRenderer(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000489{
490 mTexStorage = NULL;
491 for (int i = 0; i < 6; i++)
492 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000493 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
494 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000495 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000496 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000497 }
498}
499
500TextureCubeMap::~TextureCubeMap()
501{
502 for (int i = 0; i < 6; i++)
503 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000504 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
505 {
506 delete mImageArray[i][j];
507 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000508 }
509
510 delete mTexStorage;
511 mTexStorage = NULL;
512}
513
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000514GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
515{
516 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400517 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000518 else
519 return 0;
520}
521
522GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
523{
524 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400525 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526 else
527 return 0;
528}
529
530GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
531{
532 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400533 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000534 else
535 return GL_NONE;
536}
537
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000538GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000539{
540 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400541 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000542 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500543 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000544}
545
Geoff Lang005df412013-10-16 14:12:50 -0400546void TextureCubeMap::setImagePosX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547{
Jamie Madill88f18f42013-09-18 14:36:19 -0400548 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000549}
550
Geoff Lang005df412013-10-16 14:12:50 -0400551void TextureCubeMap::setImageNegX(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000552{
Jamie Madill88f18f42013-09-18 14:36:19 -0400553 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000554}
555
Geoff Lang005df412013-10-16 14:12:50 -0400556void TextureCubeMap::setImagePosY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000557{
Jamie Madill88f18f42013-09-18 14:36:19 -0400558 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000559}
560
Geoff Lang005df412013-10-16 14:12:50 -0400561void TextureCubeMap::setImageNegY(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000562{
Jamie Madill88f18f42013-09-18 14:36:19 -0400563 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000564}
565
Geoff Lang005df412013-10-16 14:12:50 -0400566void TextureCubeMap::setImagePosZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000567{
Jamie Madill88f18f42013-09-18 14:36:19 -0400568 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000569}
570
Geoff Lang005df412013-10-16 14:12:50 -0400571void TextureCubeMap::setImageNegZ(GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000572{
Jamie Madill88f18f42013-09-18 14:36:19 -0400573 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000574}
575
Jamie Madill2db197c2013-10-24 17:49:35 -0400576void TextureCubeMap::setCompressedImage(GLenum target, GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000577{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000578 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -0400579 int faceIndex = targetToIndex(target);
580 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000581
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582 TextureWithRenderer::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000583}
584
Jamie Madill2db197c2013-10-24 17:49:35 -0400585void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000586{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400587 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588 {
Brandon Jones6518fe22014-07-08 15:16:52 -0700589 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[faceIndex][level]);
Jamie Madill169d1112013-10-24 17:49:37 -0400590 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000592 }
593}
594
Jamie Madill88f18f42013-09-18 14:36:19 -0400595void TextureCubeMap::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000596{
Jamie Madill2db197c2013-10-24 17:49:35 -0400597 int faceIndex = targetToIndex(target);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700598 if (TextureWithRenderer::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400600 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000601 }
602}
603
604void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
605{
Jamie Madill2db197c2013-10-24 17:49:35 -0400606 int faceIndex = targetToIndex(target);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700607 if (TextureWithRenderer::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000608 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400609 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000610 }
611}
612
613// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -0400614bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000615{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400616 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000617
Jamie Madillf8989902013-07-19 16:36:58 -0400618 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000619
Geoff Langc0b9ef42014-07-02 10:02:37 -0400620 // TODO(geofflang): use context's texture caps
621 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000622 {
Jamie Madillf8989902013-07-19 16:36:58 -0400623 if (samplerState.magFilter != GL_NEAREST ||
624 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000625 {
626 return false;
627 }
628 }
629
Geoff Langc0b9ef42014-07-02 10:02:37 -0400630 // TODO(geofflang): use context's extensions
631 if (!isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000632 {
Jamie Madillf8989902013-07-19 16:36:58 -0400633 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000634 {
635 return false;
636 }
637 }
638
639 if (!mipmapping)
640 {
641 if (!isCubeComplete())
642 {
643 return false;
644 }
645 }
646 else
647 {
648 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
649 {
650 return false;
651 }
652 }
653
654 return true;
655}
656
657// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
658bool TextureCubeMap::isCubeComplete() const
659{
Jamie Madillc1f8b162013-10-07 10:46:38 -0400660 int baseWidth = getBaseLevelWidth();
661 int baseHeight = getBaseLevelHeight();
662 GLenum baseFormat = getBaseLevelInternalFormat();
663
664 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000665 {
666 return false;
667 }
668
Jamie Madill2db197c2013-10-24 17:49:35 -0400669 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000670 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400671 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -0400672
673 if (faceBaseImage.getWidth() != baseWidth ||
674 faceBaseImage.getHeight() != baseHeight ||
675 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000676 {
677 return false;
678 }
679 }
680
681 return true;
682}
683
684bool TextureCubeMap::isMipmapCubeComplete() const
685{
686 if (isImmutable())
687 {
688 return true;
689 }
690
691 if (!isCubeComplete())
692 {
693 return false;
694 }
695
Geoff Lang98705b72014-03-31 16:00:03 -0400696 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000697
698 for (int face = 0; face < 6; face++)
699 {
Geoff Lang98705b72014-03-31 16:00:03 -0400700 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000701 {
Jamie Madill07edd442013-07-19 16:36:58 -0400702 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000703 {
704 return false;
705 }
706 }
707 }
708
709 return true;
710}
711
Jamie Madill2db197c2013-10-24 17:49:35 -0400712bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -0400713{
Jamie Madill2db197c2013-10-24 17:49:35 -0400714 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -0400715
716 if (isImmutable())
717 {
718 return true;
719 }
720
Jamie Madilld3d2a342013-10-07 10:46:35 -0400721 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -0400722
Jamie Madilld3d2a342013-10-07 10:46:35 -0400723 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -0400724 {
725 return false;
726 }
727
Jamie Madilld3d2a342013-10-07 10:46:35 -0400728 // "isCubeComplete" checks for base level completeness and we must call that
729 // to determine if any face at level 0 is complete. We omit that check here
730 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -0400731 if (level == 0)
732 {
733 return true;
734 }
735
Jamie Madilld3d2a342013-10-07 10:46:35 -0400736 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -0400737 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -0400738
Jamie Madilld3d2a342013-10-07 10:46:35 -0400739 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400740 {
741 return false;
742 }
743
Jamie Madilld3d2a342013-10-07 10:46:35 -0400744 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -0400745 {
746 return false;
747 }
748
749 return true;
750}
751
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000752bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
753{
Geoff Lange4a492b2014-06-19 14:14:41 -0400754 return IsFormatCompressed(getInternalFormat(target, level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000755}
756
Geoff Lang8040f572013-07-25 16:49:54 -0400757bool TextureCubeMap::isDepth(GLenum target, GLint level) const
758{
Geoff Lange4a492b2014-06-19 14:14:41 -0400759 return GetDepthBits(getInternalFormat(target, level)) > 0;
Geoff Lang8040f572013-07-25 16:49:54 -0400760}
761
Jamie Madill73b5d062013-10-24 17:49:38 -0400762void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000763{
Jamie Madill3c0989c2013-10-24 17:49:39 -0400764 // Only initialize the first time this texture is used as a render target or shader resource
765 if (mTexStorage)
766 {
767 return;
768 }
769
770 // do not attempt to create storage for nonexistant data
771 if (!isFaceLevelComplete(0, 0))
772 {
773 return;
774 }
775
776 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
777
778 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
779 ASSERT(mTexStorage);
780
781 // flush image data to the storage
782 updateStorage();
783}
784
785rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
786{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400787 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000788
Jamie Madill3c0989c2013-10-24 17:49:39 -0400789 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000790
Jamie Madill3c0989c2013-10-24 17:49:39 -0400791 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400792 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000793
Nicolas Capensbf712d02014-03-31 14:23:35 -0400794 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -0400795}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000796
Jamie Madill3c0989c2013-10-24 17:49:39 -0400797void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
798{
799 SafeDelete(mTexStorage);
800 mTexStorage = newCompleteTexStorage;
801
802 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000803 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400804 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000805 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400806 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000807 {
Brandon Jones6518fe22014-07-08 15:16:52 -0700808 rx::ImageD3D::makeImageD3D(mImageArray[faceIndex][level])->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000809 }
810 }
811 }
812
813 mDirtyImages = true;
814}
815
Jamie Madill169d1112013-10-24 17:49:37 -0400816void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000817{
Geoff Lang946b9482014-05-12 16:37:25 -0400818 ASSERT(mTexStorage != NULL);
819 GLint storageLevels = mTexStorage->getLevelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000820 for (int face = 0; face < 6; face++)
821 {
Geoff Lang946b9482014-05-12 16:37:25 -0400822 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000823 {
Geoff Lang946b9482014-05-12 16:37:25 -0400824 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400825 {
Jamie Madill169d1112013-10-24 17:49:37 -0400826 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400827 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000828 }
829 }
830}
831
Jamie Madill169d1112013-10-24 17:49:37 -0400832void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400833{
Jamie Madill2db197c2013-10-24 17:49:35 -0400834 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
835 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -0400836
837 if (image->isDirty())
838 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400839 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -0400840 }
841}
842
Jamie Madille83d1a92013-10-24 17:49:33 -0400843bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000844{
Jamie Madill3c0989c2013-10-24 17:49:39 -0400845 initializeStorage(true);
846
847 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400848 {
Jamie Madill3c0989c2013-10-24 17:49:39 -0400849 ASSERT(mTexStorage);
850 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000851 {
Jamie Madill3c0989c2013-10-24 17:49:39 -0400852 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
853
854 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000855 {
Jamie Madill3c0989c2013-10-24 17:49:39 -0400856 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400857 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858 }
Jamie Madill3c0989c2013-10-24 17:49:39 -0400859
860 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000861 }
862 }
863
Jamie Madille83d1a92013-10-24 17:49:33 -0400864 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000865}
866
Geoff Lang005df412013-10-16 14:12:50 -0400867void TextureCubeMap::setImage(int faceIndex, GLint level, GLsizei width, GLsizei height, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000868{
Geoff Lange4a492b2014-06-19 14:14:41 -0400869 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
870 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000871
872 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000873
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700874 TextureWithRenderer::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875}
876
Jamie Madill2db197c2013-10-24 17:49:35 -0400877int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000878{
879 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
880 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
881 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
882 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
883 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
884
Jamie Madill2db197c2013-10-24 17:49:35 -0400885 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000886}
887
Jamie Madill2db197c2013-10-24 17:49:35 -0400888void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000889{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000890 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400891 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
892 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400893 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000894
Jamie Madill2db197c2013-10-24 17:49:35 -0400895 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000896
897 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400899 const int storageLevels = mTexStorage->getLevelCount();
900
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000901 if ((level >= storageLevels && storageLevels != 0) ||
902 width != storageWidth ||
903 height != storageHeight ||
904 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000905 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400906 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000907 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400908 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000909 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400910 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000911 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000912 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000913
914 delete mTexStorage;
915 mTexStorage = NULL;
916
917 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000918 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000919 }
920}
921
922void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
923{
Jamie Madill2db197c2013-10-24 17:49:35 -0400924 int faceIndex = targetToIndex(target);
Geoff Lange4a492b2014-06-19 14:14:41 -0400925 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
926 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
Jamie Madill2db197c2013-10-24 17:49:35 -0400927 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000928
Jamie Madill2db197c2013-10-24 17:49:35 -0400929 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000930 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400931 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000932 mDirtyImages = true;
933 }
934 else
935 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400936 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -0400937 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000938
939 ASSERT(width == height);
940
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400941 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000942 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000943 gl::Rectangle sourceRect;
944 sourceRect.x = x;
945 sourceRect.width = width;
946 sourceRect.y = y;
947 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000949 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000950 }
951 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000952}
953
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000954void TextureCubeMap::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000955{
Jamie Madill2db197c2013-10-24 17:49:35 -0400956 int faceIndex = targetToIndex(target);
957
Jamie Madilld3d2a342013-10-07 10:46:35 -0400958 // We can only make our texture storage to a render target if the level we're copying *to* is complete
959 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
960 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -0400961 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -0400962
Jamie Madill2db197c2013-10-24 17:49:35 -0400963 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000964 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400965 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000966 mDirtyImages = true;
967 }
968 else
969 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400970 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000971
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400972 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973 {
Jamie Madill169d1112013-10-24 17:49:37 -0400974 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -0400975
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000976 gl::Rectangle sourceRect;
977 sourceRect.x = x;
978 sourceRect.width = width;
979 sourceRect.y = y;
980 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000981
Geoff Lange4a492b2014-06-19 14:14:41 -0400982 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000983 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000984 }
985 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000986}
987
988void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
989{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990 for (int level = 0; level < levels; level++)
991 {
Geoff Langd3110192013-09-24 11:52:47 -0400992 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -0400993 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000994 {
Jamie Madill2db197c2013-10-24 17:49:35 -0400995 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000996 }
997 }
998
999 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1000 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001001 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001002 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001003 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001004 }
1005 }
1006
Jamie Madill3c0989c2013-10-24 17:49:39 -04001007 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001008
Nicolas Capensbf712d02014-03-31 14:23:35 -04001009 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010}
1011
1012void TextureCubeMap::generateMipmaps()
1013{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001014 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001015 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001016 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 {
Geoff Lang98705b72014-03-31 16:00:03 -04001018 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001020 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1021 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001022 }
1023 }
1024
1025 if (mTexStorage && mTexStorage->isRenderTarget())
1026 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001027 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028 {
Geoff Lang98705b72014-03-31 16:00:03 -04001029 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001030 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001031 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001032
Jamie Madill2db197c2013-10-24 17:49:35 -04001033 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034 }
1035 }
1036 }
1037 else
1038 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001039 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001040 {
Geoff Lang98705b72014-03-31 16:00:03 -04001041 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001042 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001043 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001044 }
1045 }
1046 }
1047}
1048
Jamie Madilld3d2a342013-10-07 10:46:35 -04001049const rx::Image *TextureCubeMap::getBaseLevelImage() const
1050{
1051 // Note: if we are not cube-complete, there is no single base level image that can describe all
1052 // cube faces, so this method is only well-defined for a cube-complete base level.
1053 return mImageArray[0][0];
1054}
1055
Jamie Madill2ebab852013-10-24 17:49:42 -04001056rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1057{
1058 return mTexStorage;
1059}
1060
Jamie Madill2db197c2013-10-24 17:49:35 -04001061unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001062{
Jamie Madill2db197c2013-10-24 17:49:35 -04001063 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001064}
1065
1066rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001067{
1068 ASSERT(IsCubemapTextureTarget(target));
1069
1070 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001071 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001072 {
1073 return NULL;
1074 }
1075
Jamie Madill169d1112013-10-24 17:49:37 -04001076 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001077
1078 // ensure this is NOT a depth texture
1079 if (isDepth(target, level))
1080 {
1081 return NULL;
1082 }
1083
1084 return mTexStorage->getRenderTarget(target, level);
1085}
1086
1087rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1088{
1089 ASSERT(IsCubemapTextureTarget(target));
1090
1091 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001092 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001093 {
1094 return NULL;
1095 }
1096
Jamie Madill169d1112013-10-24 17:49:37 -04001097 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001098
1099 // ensure this is a depth texture
1100 if (!isDepth(target, level))
1101 {
1102 return NULL;
1103 }
1104
1105 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106}
1107
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001108bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001109{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001110 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001111}
1112
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001113Texture3D::Texture3D(rx::Renderer *renderer, GLuint id)
1114 : TextureWithRenderer(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001115{
1116 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001117
1118 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1119 {
1120 mImageArray[i] = renderer->createImage();
1121 }
1122}
1123
1124Texture3D::~Texture3D()
1125{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001126 delete mTexStorage;
1127 mTexStorage = NULL;
1128
1129 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1130 {
1131 delete mImageArray[i];
1132 }
1133}
1134
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001135GLsizei Texture3D::getWidth(GLint level) const
1136{
1137 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1138}
1139
1140GLsizei Texture3D::getHeight(GLint level) const
1141{
1142 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1143}
1144
1145GLsizei Texture3D::getDepth(GLint level) const
1146{
1147 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1148}
1149
1150GLenum Texture3D::getInternalFormat(GLint level) const
1151{
1152 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1153}
1154
1155GLenum Texture3D::getActualFormat(GLint level) const
1156{
Geoff Langcbf727a2014-02-10 12:50:45 -05001157 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001158}
1159
1160bool Texture3D::isCompressed(GLint level) const
1161{
Geoff Lange4a492b2014-06-19 14:14:41 -04001162 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001163}
1164
1165bool Texture3D::isDepth(GLint level) const
1166{
Geoff Lange4a492b2014-06-19 14:14:41 -04001167 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001168}
1169
Geoff Lang005df412013-10-16 14:12:50 -04001170void Texture3D::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001171{
Geoff Lange4a492b2014-06-19 14:14:41 -04001172 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1173 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001174 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001175
Jamie Madilla2d4e552013-10-10 15:12:01 -04001176 bool fastUnpacked = false;
1177
1178 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1179 if (isFastUnpackable(unpack, sizedInternalFormat))
1180 {
1181 // Will try to create RT storage if it does not exist
1182 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1183 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1184
1185 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1186 {
1187 // Ensure we don't overwrite our newly initialized data
1188 mImageArray[level]->markClean();
1189
1190 fastUnpacked = true;
1191 }
1192 }
1193
1194 if (!fastUnpacked)
1195 {
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001196 TextureWithRenderer::setImage(unpack, type, pixels, mImageArray[level]);
Jamie Madilla2d4e552013-10-10 15:12:01 -04001197 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001198}
1199
1200void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1201{
1202 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1203 redefineImage(level, format, width, height, depth);
1204
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001205 TextureWithRenderer::setCompressedImage(imageSize, pixels, mImageArray[level]);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001206}
1207
Jamie Madill88f18f42013-09-18 14:36:19 -04001208void Texture3D::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001209{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001210 bool fastUnpacked = false;
1211
1212 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1213 if (isFastUnpackable(unpack, getInternalFormat(level)))
1214 {
1215 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1216 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1217
1218 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1219 {
1220 // Ensure we don't overwrite our newly initialized data
1221 mImageArray[level]->markClean();
1222
1223 fastUnpacked = true;
1224 }
1225 }
1226
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001227 if (!fastUnpacked && TextureWithRenderer::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001228 {
1229 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1230 }
1231}
1232
1233void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1234{
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001235 if (TextureWithRenderer::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001236 {
1237 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1238 }
1239}
1240
1241void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1242{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001243 for (int level = 0; level < levels; level++)
1244 {
Jamie Madille664e202013-10-24 17:49:40 -04001245 GLsizei levelWidth = std::max(1, width >> level);
1246 GLsizei levelHeight = std::max(1, height >> level);
1247 GLsizei levelDepth = std::max(1, depth >> level);
1248 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001249 }
1250
1251 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1252 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001253 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001254 }
1255
Jamie Madille664e202013-10-24 17:49:40 -04001256 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001257
Nicolas Capensbf712d02014-03-31 14:23:35 -04001258 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001259}
1260
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001261void Texture3D::generateMipmaps()
1262{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001263 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001264 int levelCount = mipLevels();
1265 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001266 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001267 redefineImage(level, getBaseLevelInternalFormat(),
1268 std::max(getBaseLevelWidth() >> level, 1),
1269 std::max(getBaseLevelHeight() >> level, 1),
1270 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001271 }
1272
1273 if (mTexStorage && mTexStorage->isRenderTarget())
1274 {
Geoff Lang98705b72014-03-31 16:00:03 -04001275 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001276 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001277 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001278
Jamie Madill22f843a2013-10-24 17:49:36 -04001279 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001280 }
1281 }
1282 else
1283 {
Geoff Lang98705b72014-03-31 16:00:03 -04001284 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001285 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001286 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001287 }
1288 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001289}
1290
Jamie Madilld3d2a342013-10-07 10:46:35 -04001291const rx::Image *Texture3D::getBaseLevelImage() const
1292{
1293 return mImageArray[0];
1294}
1295
Jamie Madill2ebab852013-10-24 17:49:42 -04001296rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1297{
1298 return mTexStorage;
1299}
1300
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001301void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1302{
Jamie Madill07edd442013-07-19 16:36:58 -04001303 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1304 // the current level we're copying to is defined (with appropriate format, width & height)
1305 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1306
1307 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001308 {
1309 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1310 mDirtyImages = true;
1311 }
1312 else
1313 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001314 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001315
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001316 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001317 {
Jamie Madill169d1112013-10-24 17:49:37 -04001318 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001319
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001320 gl::Rectangle sourceRect;
1321 sourceRect.x = x;
1322 sourceRect.width = width;
1323 sourceRect.y = y;
1324 sourceRect.height = height;
1325
1326 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -04001327 gl::GetFormat(getBaseLevelInternalFormat()),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001328 xoffset, yoffset, zoffset, mTexStorage, level);
1329 }
1330 }
1331}
1332
Jamie Madillf8989902013-07-19 16:36:58 -04001333bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001334{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001335 GLsizei width = getBaseLevelWidth();
1336 GLsizei height = getBaseLevelHeight();
1337 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001338
1339 if (width <= 0 || height <= 0 || depth <= 0)
1340 {
1341 return false;
1342 }
1343
Geoff Langc0b9ef42014-07-02 10:02:37 -04001344 // TODO(geofflang): use context's texture caps
1345 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001346 {
Jamie Madillf8989902013-07-19 16:36:58 -04001347 if (samplerState.magFilter != GL_NEAREST ||
1348 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001349 {
1350 return false;
1351 }
1352 }
1353
Jamie Madillf8989902013-07-19 16:36:58 -04001354 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001355 {
1356 return false;
1357 }
1358
1359 return true;
1360}
1361
1362bool Texture3D::isMipmapComplete() const
1363{
Geoff Lang98705b72014-03-31 16:00:03 -04001364 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001365
Geoff Lang98705b72014-03-31 16:00:03 -04001366 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001367 {
1368 if (!isLevelComplete(level))
1369 {
1370 return false;
1371 }
1372 }
1373
1374 return true;
1375}
1376
1377bool Texture3D::isLevelComplete(int level) const
1378{
1379 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1380
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001381 if (isImmutable())
1382 {
1383 return true;
1384 }
1385
Jamie Madilld3d2a342013-10-07 10:46:35 -04001386 GLsizei width = getBaseLevelWidth();
1387 GLsizei height = getBaseLevelHeight();
1388 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001389
1390 if (width <= 0 || height <= 0 || depth <= 0)
1391 {
1392 return false;
1393 }
1394
Jamie Madill07edd442013-07-19 16:36:58 -04001395 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001396 {
Jamie Madill07edd442013-07-19 16:36:58 -04001397 return true;
1398 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001399
Jamie Madill07edd442013-07-19 16:36:58 -04001400 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001401
Jamie Madilld3d2a342013-10-07 10:46:35 -04001402 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001403 {
1404 return false;
1405 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001406
Jamie Madill07edd442013-07-19 16:36:58 -04001407 if (levelImage->getWidth() != std::max(1, width >> level))
1408 {
1409 return false;
1410 }
1411
1412 if (levelImage->getHeight() != std::max(1, height >> level))
1413 {
1414 return false;
1415 }
1416
1417 if (levelImage->getDepth() != std::max(1, depth >> level))
1418 {
1419 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001420 }
1421
1422 return true;
1423}
1424
Geoff Lang8040f572013-07-25 16:49:54 -04001425unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1426{
Jamie Madille83d1a92013-10-24 17:49:33 -04001427 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001428}
1429
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001430bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001431{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001432 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001433}
1434
Jamie Madill73b5d062013-10-24 17:49:38 -04001435void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001436{
Jamie Madille664e202013-10-24 17:49:40 -04001437 // Only initialize the first time this texture is used as a render target or shader resource
1438 if (mTexStorage)
1439 {
1440 return;
1441 }
1442
1443 // do not attempt to create storage for nonexistant data
1444 if (!isLevelComplete(0))
1445 {
1446 return;
1447 }
1448
1449 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1450
1451 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1452 ASSERT(mTexStorage);
1453
1454 // flush image data to the storage
1455 updateStorage();
1456}
1457
1458rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
1459{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001460 GLsizei width = getBaseLevelWidth();
1461 GLsizei height = getBaseLevelHeight();
1462 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001463
Jamie Madille664e202013-10-24 17:49:40 -04001464 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001465
Jamie Madille664e202013-10-24 17:49:40 -04001466 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001467 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001468
Nicolas Capensbf712d02014-03-31 14:23:35 -04001469 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04001470}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001471
Jamie Madille664e202013-10-24 17:49:40 -04001472void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
1473{
1474 SafeDelete(mTexStorage);
1475 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001476 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04001477
1478 // We do not support managed 3D storage, as that is D3D9/ES2-only
1479 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001480}
1481
Jamie Madill169d1112013-10-24 17:49:37 -04001482void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001483{
Geoff Lang946b9482014-05-12 16:37:25 -04001484 ASSERT(mTexStorage != NULL);
1485 GLint storageLevels = mTexStorage->getLevelCount();
1486 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001487 {
Geoff Lang946b9482014-05-12 16:37:25 -04001488 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001489 {
Jamie Madill169d1112013-10-24 17:49:37 -04001490 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001491 }
Jamie Madill07edd442013-07-19 16:36:58 -04001492 }
1493}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001494
Jamie Madill169d1112013-10-24 17:49:37 -04001495void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001496{
1497 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04001498 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04001499
Jamie Madillaee7ad82013-10-10 16:07:32 -04001500 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04001501 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04001502 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001503 }
1504}
1505
Jamie Madille83d1a92013-10-24 17:49:33 -04001506bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001507{
Jamie Madille664e202013-10-24 17:49:40 -04001508 initializeStorage(true);
1509
1510 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001511 {
Jamie Madille664e202013-10-24 17:49:40 -04001512 ASSERT(mTexStorage);
1513 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001514 {
Jamie Madille664e202013-10-24 17:49:40 -04001515 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1516
1517 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001518 {
Jamie Madille664e202013-10-24 17:49:40 -04001519 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001520 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001521 }
Jamie Madille664e202013-10-24 17:49:40 -04001522
1523 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001524 }
1525 }
1526
Jamie Madille83d1a92013-10-24 17:49:33 -04001527 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001528}
1529
Jamie Madilla2d4e552013-10-10 15:12:01 -04001530rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
1531{
1532 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001533 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04001534 {
1535 return NULL;
1536 }
1537
Jamie Madill169d1112013-10-24 17:49:37 -04001538 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04001539
1540 // ensure this is NOT a depth texture
1541 if (isDepth(level))
1542 {
1543 return NULL;
1544 }
1545
1546 return mTexStorage->getRenderTarget(level);
1547}
1548
Geoff Lang8040f572013-07-25 16:49:54 -04001549rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001550{
Geoff Lang8040f572013-07-25 16:49:54 -04001551 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001552 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001553 {
1554 return NULL;
1555 }
1556
Jamie Madill169d1112013-10-24 17:49:37 -04001557 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04001558
1559 // ensure this is NOT a depth texture
1560 if (isDepth(level))
1561 {
1562 return NULL;
1563 }
1564
1565 return mTexStorage->getRenderTarget(level, layer);
1566}
1567
1568rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
1569{
1570 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001571 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001572 {
1573 return NULL;
1574 }
1575
Jamie Madill169d1112013-10-24 17:49:37 -04001576 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001577
1578 // ensure this is a depth texture
1579 if (!isDepth(level))
1580 {
1581 return NULL;
1582 }
1583
1584 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001585}
1586
Geoff Lang005df412013-10-16 14:12:50 -04001587void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001588{
1589 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001590 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1591 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1592 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001593 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001594
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001595 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001596
1597 if (mTexStorage)
1598 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001599 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001600
1601 if ((level >= storageLevels && storageLevels != 0) ||
1602 width != storageWidth ||
1603 height != storageHeight ||
1604 depth != storageDepth ||
1605 internalformat != storageFormat) // Discard mismatched storage
1606 {
1607 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1608 {
1609 mImageArray[i]->markDirty();
1610 }
1611
1612 delete mTexStorage;
1613 mTexStorage = NULL;
1614 mDirtyImages = true;
1615 }
1616 }
1617}
1618
1619void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
1620{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001621 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001622 {
Brandon Jones6518fe22014-07-08 15:16:52 -07001623 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[level]);
Jamie Madill169d1112013-10-24 17:49:37 -04001624 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001625 {
1626 image->markClean();
1627 }
1628 }
1629}
1630
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001631Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id)
1632 : TextureWithRenderer(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001633{
1634 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001635
1636 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1637 {
1638 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001639 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001640 }
1641}
1642
1643Texture2DArray::~Texture2DArray()
1644{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001645 delete mTexStorage;
1646 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04001647
1648 deleteImages();
1649}
1650
1651void Texture2DArray::deleteImages()
1652{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001653 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1654 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001655 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001656 {
1657 delete mImageArray[level][layer];
1658 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001659 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04001660 mImageArray[level] = NULL;
1661 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001662 }
1663}
1664
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001665GLsizei Texture2DArray::getWidth(GLint level) const
1666{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001667 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001668}
1669
1670GLsizei Texture2DArray::getHeight(GLint level) const
1671{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001672 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001673}
1674
Jamie Madillb8f8b892014-01-07 10:12:50 -05001675GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001676{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001677 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001678}
1679
1680GLenum Texture2DArray::getInternalFormat(GLint level) const
1681{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001682 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001683}
1684
1685GLenum Texture2DArray::getActualFormat(GLint level) const
1686{
Geoff Langcbf727a2014-02-10 12:50:45 -05001687 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001688}
1689
1690bool Texture2DArray::isCompressed(GLint level) const
1691{
Geoff Lange4a492b2014-06-19 14:14:41 -04001692 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001693}
1694
1695bool Texture2DArray::isDepth(GLint level) const
1696{
Geoff Lange4a492b2014-06-19 14:14:41 -04001697 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001698}
1699
Geoff Lang005df412013-10-16 14:12:50 -04001700void Texture2DArray::setImage(GLint level, GLsizei width, GLsizei height, GLsizei depth, GLenum internalFormat, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001701{
Geoff Lange4a492b2014-06-19 14:14:41 -04001702 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1703 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001704 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001705
Geoff Lange4a492b2014-06-19 14:14:41 -04001706 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001707
1708 for (int i = 0; i < depth; i++)
1709 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04001710 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001711 TextureWithRenderer::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001712 }
1713}
1714
1715void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1716{
1717 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1718 redefineImage(level, format, width, height, depth);
1719
Geoff Lange4a492b2014-06-19 14:14:41 -04001720 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001721
1722 for (int i = 0; i < depth; i++)
1723 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04001724 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001725 TextureWithRenderer::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001726 }
1727}
1728
Jamie Madill88f18f42013-09-18 14:36:19 -04001729void Texture2DArray::subImage(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001730{
Geoff Lang005df412013-10-16 14:12:50 -04001731 GLenum internalformat = getInternalFormat(level);
Geoff Lange4a492b2014-06-19 14:14:41 -04001732 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001733
1734 for (int i = 0; i < depth; i++)
1735 {
1736 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04001737 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001738
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001739 if (TextureWithRenderer::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack, layerPixels, mImageArray[level][layer]))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001740 {
1741 commitRect(level, xoffset, yoffset, layer, width, height);
1742 }
1743 }
1744}
1745
1746void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1747{
Geoff Lange4a492b2014-06-19 14:14:41 -04001748 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001749
1750 for (int i = 0; i < depth; i++)
1751 {
1752 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04001753 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001754
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001755 if (TextureWithRenderer::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001756 {
1757 commitRect(level, xoffset, yoffset, layer, width, height);
1758 }
1759 }
1760}
1761
1762void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1763{
Jamie Madill884a4622013-10-24 17:49:41 -04001764 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001765
1766 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1767 {
Jamie Madill884a4622013-10-24 17:49:41 -04001768 GLsizei levelWidth = std::max(1, width >> level);
1769 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001770
Jamie Madill884a4622013-10-24 17:49:41 -04001771 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001772
Jamie Madill884a4622013-10-24 17:49:41 -04001773 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001774 {
1775 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04001776 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001777
1778 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001779 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00001780 mImageArray[level][layer] = mRenderer->createImage();
1781 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
1782 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001783 }
1784 }
1785 }
1786
Jamie Madill884a4622013-10-24 17:49:41 -04001787 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04001788 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001789}
1790
1791void Texture2DArray::generateMipmaps()
1792{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001793 int baseWidth = getBaseLevelWidth();
1794 int baseHeight = getBaseLevelHeight();
1795 int baseDepth = getBaseLevelDepth();
1796 GLenum baseFormat = getBaseLevelInternalFormat();
1797
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00001798 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001799 int levelCount = mipLevels();
1800 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00001801 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001802 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00001803 }
1804
1805 if (mTexStorage && mTexStorage->isRenderTarget())
1806 {
Geoff Lang98705b72014-03-31 16:00:03 -04001807 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00001808 {
1809 mTexStorage->generateMipmap(level);
1810
1811 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1812 {
1813 mImageArray[level][layer]->markClean();
1814 }
1815 }
1816 }
1817 else
1818 {
Geoff Lang98705b72014-03-31 16:00:03 -04001819 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00001820 {
1821 for (int layer = 0; layer < mLayerCounts[level]; layer++)
1822 {
1823 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
1824 }
1825 }
1826 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001827}
1828
Jamie Madilld3d2a342013-10-07 10:46:35 -04001829const rx::Image *Texture2DArray::getBaseLevelImage() const
1830{
Jamie Madill152ed092013-10-09 17:01:15 -04001831 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04001832}
1833
Jamie Madill2ebab852013-10-24 17:49:42 -04001834rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
1835{
1836 return mTexStorage;
1837}
1838
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001839void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1840{
Jamie Madill07edd442013-07-19 16:36:58 -04001841 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1842 // the current level we're copying to is defined (with appropriate format, width & height)
1843 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1844
1845 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001846 {
1847 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
1848 mDirtyImages = true;
1849 }
1850 else
1851 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001852 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001853
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001854 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001855 {
Jamie Madill169d1112013-10-24 17:49:37 -04001856 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001857
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001858 gl::Rectangle sourceRect;
1859 sourceRect.x = x;
1860 sourceRect.width = width;
1861 sourceRect.y = y;
1862 sourceRect.height = height;
1863
Geoff Lange4a492b2014-06-19 14:14:41 -04001864 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001865 xoffset, yoffset, zoffset, mTexStorage, level);
1866 }
1867 }
1868}
1869
Jamie Madillf8989902013-07-19 16:36:58 -04001870bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001871{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001872 GLsizei width = getBaseLevelWidth();
1873 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05001874 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001875
1876 if (width <= 0 || height <= 0 || depth <= 0)
1877 {
1878 return false;
1879 }
1880
Geoff Langc0b9ef42014-07-02 10:02:37 -04001881 // TODO(geofflang): use context's texture caps
1882 if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filtering)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001883 {
Jamie Madillf8989902013-07-19 16:36:58 -04001884 if (samplerState.magFilter != GL_NEAREST ||
1885 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001886 {
1887 return false;
1888 }
1889 }
1890
Jamie Madillf8989902013-07-19 16:36:58 -04001891 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001892 {
1893 return false;
1894 }
1895
1896 return true;
1897}
1898
1899bool Texture2DArray::isMipmapComplete() const
1900{
Geoff Lang98705b72014-03-31 16:00:03 -04001901 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001902
Geoff Lang98705b72014-03-31 16:00:03 -04001903 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001904 {
1905 if (!isLevelComplete(level))
1906 {
1907 return false;
1908 }
1909 }
1910
1911 return true;
1912}
1913
1914bool Texture2DArray::isLevelComplete(int level) const
1915{
Jamie Madillb8f8b892014-01-07 10:12:50 -05001916 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04001917
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001918 if (isImmutable())
1919 {
1920 return true;
1921 }
1922
Jamie Madilld3d2a342013-10-07 10:46:35 -04001923 GLsizei width = getBaseLevelWidth();
1924 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05001925 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001926
Jamie Madillb8f8b892014-01-07 10:12:50 -05001927 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001928 {
1929 return false;
1930 }
1931
Jamie Madill07edd442013-07-19 16:36:58 -04001932 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001933 {
Jamie Madill07edd442013-07-19 16:36:58 -04001934 return true;
1935 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001936
Jamie Madill07edd442013-07-19 16:36:58 -04001937 if (getInternalFormat(level) != getInternalFormat(0))
1938 {
1939 return false;
1940 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001941
Jamie Madill07edd442013-07-19 16:36:58 -04001942 if (getWidth(level) != std::max(1, width >> level))
1943 {
1944 return false;
1945 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001946
Jamie Madill07edd442013-07-19 16:36:58 -04001947 if (getHeight(level) != std::max(1, height >> level))
1948 {
1949 return false;
1950 }
1951
Jamie Madillb8f8b892014-01-07 10:12:50 -05001952 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04001953 {
1954 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001955 }
1956
1957 return true;
1958}
1959
Jamie Madille83d1a92013-10-24 17:49:33 -04001960unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04001961{
Jamie Madille83d1a92013-10-24 17:49:33 -04001962 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001963}
1964
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001965bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001966{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001967 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001968}
1969
Jamie Madill73b5d062013-10-24 17:49:38 -04001970void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001971{
Jamie Madill884a4622013-10-24 17:49:41 -04001972 // Only initialize the first time this texture is used as a render target or shader resource
1973 if (mTexStorage)
1974 {
1975 return;
1976 }
1977
1978 // do not attempt to create storage for nonexistant data
1979 if (!isLevelComplete(0))
1980 {
1981 return;
1982 }
1983
1984 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1985
1986 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1987 ASSERT(mTexStorage);
1988
1989 // flush image data to the storage
1990 updateStorage();
1991}
1992
1993rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
1994{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001995 GLsizei width = getBaseLevelWidth();
1996 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05001997 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00001998
Jamie Madill884a4622013-10-24 17:49:41 -04001999 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002000
Jamie Madill884a4622013-10-24 17:49:41 -04002001 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002002 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002003
Nicolas Capensbf712d02014-03-31 14:23:35 -04002004 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002005}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002006
Jamie Madill884a4622013-10-24 17:49:41 -04002007void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2008{
2009 SafeDelete(mTexStorage);
2010 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002011 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002012
2013 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2014 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002015}
2016
Jamie Madill169d1112013-10-24 17:49:37 -04002017void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002018{
Geoff Lang946b9482014-05-12 16:37:25 -04002019 ASSERT(mTexStorage != NULL);
2020 GLint storageLevels = mTexStorage->getLevelCount();
2021 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002022 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002023 if (isLevelComplete(level))
2024 {
Jamie Madill169d1112013-10-24 17:49:37 -04002025 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002026 }
Jamie Madill07edd442013-07-19 16:36:58 -04002027 }
2028}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002029
Jamie Madill169d1112013-10-24 17:49:37 -04002030void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002031{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002032 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2033 ASSERT(isLevelComplete(level));
2034
Jamie Madill07edd442013-07-19 16:36:58 -04002035 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2036 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002037 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2038 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002039 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002040 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002041 }
2042 }
2043}
2044
Jamie Madille83d1a92013-10-24 17:49:33 -04002045bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002046{
Jamie Madill884a4622013-10-24 17:49:41 -04002047 initializeStorage(true);
2048
Jamie Madillb8f8b892014-01-07 10:12:50 -05002049 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002050 {
Jamie Madill884a4622013-10-24 17:49:41 -04002051 ASSERT(mTexStorage);
2052 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002053 {
Jamie Madill884a4622013-10-24 17:49:41 -04002054 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2055
2056 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002057 {
Jamie Madill884a4622013-10-24 17:49:41 -04002058 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002059 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002060 }
Jamie Madill884a4622013-10-24 17:49:41 -04002061
2062 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002063 }
2064 }
2065
Jamie Madille83d1a92013-10-24 17:49:33 -04002066 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002067}
2068
Geoff Lang8040f572013-07-25 16:49:54 -04002069rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002070{
Geoff Lang8040f572013-07-25 16:49:54 -04002071 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002072 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002073 {
2074 return NULL;
2075 }
2076
Jamie Madill169d1112013-10-24 17:49:37 -04002077 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002078
2079 // ensure this is NOT a depth texture
2080 if (isDepth(level))
2081 {
2082 return NULL;
2083 }
2084
2085 return mTexStorage->getRenderTarget(level, layer);
2086}
2087
2088rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2089{
2090 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002091 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002092 {
2093 return NULL;
2094 }
2095
Jamie Madill169d1112013-10-24 17:49:37 -04002096 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002097
2098 // ensure this is a depth texture
2099 if (!isDepth(level))
2100 {
2101 return NULL;
2102 }
2103
2104 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002105}
2106
Geoff Lang005df412013-10-16 14:12:50 -04002107void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002108{
2109 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002110 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2111 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002112 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002113 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002114
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002115 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002116 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002117 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002118 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002119 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002120 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002121 mLayerCounts[level] = depth;
2122
Jamie Madill152ed092013-10-09 17:01:15 -04002123 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002124 {
Jamie Madill152ed092013-10-09 17:01:15 -04002125 mImageArray[level] = new rx::Image*[depth]();
2126
2127 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2128 {
2129 mImageArray[level][layer] = mRenderer->createImage();
2130 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2131 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002132 }
2133
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002134 if (mTexStorage)
2135 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002136 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002137
2138 if ((level >= storageLevels && storageLevels != 0) ||
2139 width != storageWidth ||
2140 height != storageHeight ||
2141 depth != storageDepth ||
2142 internalformat != storageFormat) // Discard mismatched storage
2143 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002144 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002145 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002146 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002147 {
2148 mImageArray[level][layer]->markDirty();
2149 }
2150 }
2151
2152 delete mTexStorage;
2153 mTexStorage = NULL;
2154 mDirtyImages = true;
2155 }
2156 }
2157}
2158
2159void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2160{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002161 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002162 {
Brandon Jones6518fe22014-07-08 15:16:52 -07002163 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[level][layerTarget]);
Jamie Madill169d1112013-10-24 17:49:37 -04002164 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002165 {
2166 image->markClean();
2167 }
2168 }
2169}
2170
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002171}