blob: 9311ab9249ab8303e160fb1f5ed2457a418cfccf [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"
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000027
28namespace gl
29{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000030
Jamie Madillf8989902013-07-19 16:36:58 -040031bool IsMipmapFiltered(const SamplerState &samplerState)
32{
33 switch (samplerState.minFilter)
34 {
35 case GL_NEAREST:
36 case GL_LINEAR:
37 return false;
38 case GL_NEAREST_MIPMAP_NEAREST:
39 case GL_LINEAR_MIPMAP_NEAREST:
40 case GL_NEAREST_MIPMAP_LINEAR:
41 case GL_LINEAR_MIPMAP_LINEAR:
42 return true;
43 default: UNREACHABLE();
44 return false;
45 }
46}
47
Jamie Madilld4589c92013-10-24 17:49:34 -040048bool IsRenderTargetUsage(GLenum usage)
49{
50 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
51}
52
Geoff Lang4907f2c2013-07-25 12:53:57 -040053Texture::Texture(rx::Renderer *renderer, GLuint id, GLenum target) : RefCountObject(id)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000054{
daniel@transgaming.com370482e2012-11-28 19:32:13 +000055 mRenderer = renderer;
56
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000057 mUsage = GL_NONE;
Geoff Langc82fc412013-07-10 14:43:42 -040058
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000059 mDirtyImages = true;
60
61 mImmutable = false;
Geoff Lang4907f2c2013-07-25 12:53:57 -040062
63 mTarget = target;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000064}
65
66Texture::~Texture()
67{
68}
69
Geoff Lang4907f2c2013-07-25 12:53:57 -040070GLenum Texture::getTarget() const
71{
72 return mTarget;
73}
74
Geoff Lang63b5f1f2013-09-23 14:52:14 -040075void Texture::setUsage(GLenum usage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000076{
Geoff Lang63b5f1f2013-09-23 14:52:14 -040077 mUsage = usage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000078}
79
Brandon Jonesa328d562014-07-01 13:52:40 -070080void Texture::getSamplerStateWithNativeOffset(SamplerState *sampler)
daniel@transgaming.comebf139f2012-10-31 18:07:32 +000081{
82 *sampler = mSamplerState;
Nicolas Capens8de68282014-04-04 11:10:27 -040083
84 // Offset the effective base level by the texture storage's top level
85 rx::TextureStorageInterface *texture = getNativeTexture();
86 int topLevel = texture ? texture->getTopLevel() : 0;
87 sampler->baseLevel = topLevel + mSamplerState.baseLevel;
daniel@transgaming.com07ab8412012-07-12 15:17:09 +000088}
89
daniel@transgaming.com95a758f2012-07-12 15:17:06 +000090GLenum Texture::getUsage() const
91{
92 return mUsage;
93}
94
Jamie Madilld3d2a342013-10-07 10:46:35 -040095GLint Texture::getBaseLevelWidth() const
96{
97 const rx::Image *baseImage = getBaseLevelImage();
98 return (baseImage ? baseImage->getWidth() : 0);
99}
100
101GLint Texture::getBaseLevelHeight() const
102{
103 const rx::Image *baseImage = getBaseLevelImage();
104 return (baseImage ? baseImage->getHeight() : 0);
105}
106
107GLint Texture::getBaseLevelDepth() const
108{
109 const rx::Image *baseImage = getBaseLevelImage();
110 return (baseImage ? baseImage->getDepth() : 0);
111}
112
Jamie Madillb8f8b892014-01-07 10:12:50 -0500113// Note: "base level image" is loosely defined to be any image from the base level,
114// where in the base of 2D array textures and cube maps there are several. Don't use
115// the base level image for anything except querying texture format and size.
Jamie Madilld3d2a342013-10-07 10:46:35 -0400116GLenum Texture::getBaseLevelInternalFormat() const
117{
118 const rx::Image *baseImage = getBaseLevelImage();
119 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
120}
121
Jamie Madill88f18f42013-09-18 14:36:19 -0400122void Texture::setImage(const PixelUnpackState &unpack, GLenum type, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000123{
Jamie Madillc30003d2014-01-10 12:51:23 -0500124 // No-op
125 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
126 {
127 return;
128 }
129
Jamie Madillabef6802013-09-05 16:54:19 -0400130 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
131 // 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 -0400132 const void *pixelData = pixels;
133
134 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000135 {
Jamie Madill1beb1db2013-09-18 14:36:28 -0400136 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
137 Buffer *pixelBuffer = unpack.pixelBuffer.get();
138 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700139 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
140 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
141 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill1beb1db2013-09-18 14:36:28 -0400142 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
143 }
144
145 if (pixelData != NULL)
146 {
147 image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000148 mDirtyImages = true;
149 }
150}
151
Geoff Lang005df412013-10-16 14:12:50 -0400152bool Texture::isFastUnpackable(const PixelUnpackState &unpack, GLenum sizedInternalFormat)
Jamie Madill8cc7d972013-10-10 15:51:55 -0400153{
154 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
155}
156
Jamie Madill1beb1db2013-09-18 14:36:28 -0400157bool Texture::fastUnpackPixels(const PixelUnpackState &unpack, const void *pixels, const Box &destArea,
Jamie Madill8cc7d972013-10-10 15:51:55 -0400158 GLenum sizedInternalFormat, GLenum type, rx::RenderTarget *destRenderTarget)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400159{
160 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
161 {
162 return true;
163 }
164
165 // In order to perform the fast copy through the shader, we must have the right format, and be able
166 // to create a render target.
Jamie Madill8cc7d972013-10-10 15:51:55 -0400167 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
Jamie Madill1beb1db2013-09-18 14:36:28 -0400168
Jamie Madill8cc7d972013-10-10 15:51:55 -0400169 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400170
Jamie Madill8cc7d972013-10-10 15:51:55 -0400171 return mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
Jamie Madill1beb1db2013-09-18 14:36:28 -0400172}
173
daniel@transgaming.com31b13e12012-11-28 19:34:30 +0000174void Texture::setCompressedImage(GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000175{
176 if (pixels != NULL)
177 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000178 image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000179 mDirtyImages = true;
180 }
181}
182
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000183bool Texture::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madill88f18f42013-09-18 14:36:19 -0400184 GLenum format, GLenum type, const PixelUnpackState &unpack, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000185{
Jamie Madill065e1a32013-10-10 15:11:50 -0400186 const void *pixelData = pixels;
187
188 // CPU readback & copy where direct GPU copy is not supported
189 if (unpack.pixelBuffer.id() != 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000190 {
Jamie Madill065e1a32013-10-10 15:11:50 -0400191 Buffer *pixelBuffer = unpack.pixelBuffer.get();
192 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
Brandon Jonesd38f9262014-06-18 16:26:45 -0700193 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
194 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
195 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill065e1a32013-10-10 15:11:50 -0400196 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
197 }
198
199 if (pixelData != NULL)
200 {
201 image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment, type, pixelData);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000202 mDirtyImages = true;
203 }
204
205 return true;
206}
207
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000208bool Texture::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
209 GLenum format, GLsizei imageSize, const void *pixels, rx::Image *image)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000210{
211 if (pixels != NULL)
212 {
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000213 image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000214 mDirtyImages = true;
215 }
216
217 return true;
218}
219
daniel@transgaming.com87705f82012-12-20 21:10:45 +0000220rx::TextureStorageInterface *Texture::getNativeTexture()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000221{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000222 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400223 initializeStorage(false);
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000224
Jamie Madill2ebab852013-10-24 17:49:42 -0400225 rx::TextureStorageInterface *storage = getBaseLevelStorage();
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000226 if (storage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000227 {
Jamie Madill169d1112013-10-24 17:49:37 -0400228 updateStorage();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000229 }
230
daniel@transgaming.com9d4346f2012-10-31 19:52:04 +0000231 return storage;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000232}
233
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000234bool Texture::hasDirtyImages() const
235{
236 return mDirtyImages;
237}
238
239void Texture::resetDirty()
240{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000241 mDirtyImages = false;
242}
243
244unsigned int Texture::getTextureSerial()
245{
Jamie Madill2ebab852013-10-24 17:49:42 -0400246 rx::TextureStorageInterface *texture = getNativeTexture();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000247 return texture ? texture->getTextureSerial() : 0;
248}
249
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000250bool Texture::isImmutable() const
251{
252 return mImmutable;
253}
254
Jamie Madill51a94372013-10-24 17:49:43 -0400255int Texture::immutableLevelCount()
256{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400257 return (mImmutable ? getNativeTexture()->getStorageInstance()->getLevelCount() : 0);
Jamie Madill51a94372013-10-24 17:49:43 -0400258}
259
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000260GLint Texture::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
261{
Geoff Langc0b9ef42014-07-02 10:02:37 -0400262 // TODO(geofflang): use context's extensions
263 if ((isPow2(width) && isPow2(height) && isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000264 {
Jamie Madill6b7440c2013-10-24 17:49:47 -0400265 // Maximum number of levels
Geoff Lang98705b72014-03-31 16:00:03 -0400266 return log2(std::max(std::max(width, height), depth)) + 1;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000267 }
268 else
269 {
270 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
271 return 1;
272 }
273}
274
Jamie Madill22f843a2013-10-24 17:49:36 -0400275int Texture::mipLevels() const
276{
Geoff Lang98705b72014-03-31 16:00:03 -0400277 return log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
Jamie Madill22f843a2013-10-24 17:49:36 -0400278}
279
Geoff Lang4907f2c2013-07-25 12:53:57 -0400280Texture2D::Texture2D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000281{
282 mTexStorage = NULL;
283 mSurface = NULL;
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000284
285 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
286 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000287 mImageArray[i] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000288 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000289}
290
291Texture2D::~Texture2D()
292{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000293 delete mTexStorage;
294 mTexStorage = NULL;
295
296 if (mSurface)
297 {
298 mSurface->setBoundTexture(NULL);
299 mSurface = NULL;
300 }
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000301
302 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
303 {
304 delete mImageArray[i];
305 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000306}
307
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000308GLsizei Texture2D::getWidth(GLint level) const
309{
310 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000311 return mImageArray[level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000312 else
313 return 0;
314}
315
316GLsizei Texture2D::getHeight(GLint level) const
317{
318 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000319 return mImageArray[level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000320 else
321 return 0;
322}
323
324GLenum Texture2D::getInternalFormat(GLint level) const
325{
326 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000327 return mImageArray[level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000328 else
329 return GL_NONE;
330}
331
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000332GLenum Texture2D::getActualFormat(GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000333{
334 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000335 return mImageArray[level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000336 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500337 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000338}
339
Geoff Lang005df412013-10-16 14:12:50 -0400340void Texture2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000341{
342 releaseTexImage();
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000343
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000344 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -0400345 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
346 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -0400347 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000348
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000349 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000350
351 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000352 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400353 const int storageLevels = mTexStorage->getLevelCount();
354
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000355 if ((level >= storageLevels && storageLevels != 0) ||
356 width != storageWidth ||
357 height != storageHeight ||
358 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000359 {
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000360 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
361 {
362 mImageArray[i]->markDirty();
363 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000364
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +0000365 delete mTexStorage;
366 mTexStorage = NULL;
367 mDirtyImages = true;
368 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000369 }
370}
371
Geoff Lang005df412013-10-16 14:12:50 -0400372void 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 +0000373{
Geoff Lange4a492b2014-06-19 14:14:41 -0400374 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
375 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +0000376 redefineImage(level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000377
Jamie Madill8cc7d972013-10-10 15:51:55 -0400378 bool fastUnpacked = false;
379
Jamie Madill1beb1db2013-09-18 14:36:28 -0400380 // Attempt a fast gpu copy of the pixel data to the surface
Jamie Madill8cc7d972013-10-10 15:51:55 -0400381 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
Jamie Madill1beb1db2013-09-18 14:36:28 -0400382 {
Jamie Madill8cc7d972013-10-10 15:51:55 -0400383 // Will try to create RT storage if it does not exist
384 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
385 Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
386
387 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
388 {
389 // Ensure we don't overwrite our newly initialized data
390 mImageArray[level]->markClean();
391
392 fastUnpacked = true;
393 }
Jamie Madill1beb1db2013-09-18 14:36:28 -0400394 }
Jamie Madill8cc7d972013-10-10 15:51:55 -0400395
396 if (!fastUnpacked)
Jamie Madill1beb1db2013-09-18 14:36:28 -0400397 {
398 Texture::setImage(unpack, type, pixels, mImageArray[level]);
399 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000400}
401
402void Texture2D::bindTexImage(egl::Surface *surface)
403{
404 releaseTexImage();
405
Geoff Lang005df412013-10-16 14:12:50 -0400406 GLenum internalformat = surface->getFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000407
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000408 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000409
410 delete mTexStorage;
daniel@transgaming.comd8353dd2012-12-20 21:11:14 +0000411 mTexStorage = new rx::TextureStorageInterface2D(mRenderer, surface->getSwapChain());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000412
413 mDirtyImages = true;
414 mSurface = surface;
415 mSurface->setBoundTexture(this);
416}
417
418void Texture2D::releaseTexImage()
419{
420 if (mSurface)
421 {
422 mSurface->setBoundTexture(NULL);
423 mSurface = NULL;
424
425 if (mTexStorage)
426 {
427 delete mTexStorage;
428 mTexStorage = NULL;
429 }
430
431 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
432 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000433 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000434 }
435 }
436}
437
438void Texture2D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei imageSize, const void *pixels)
439{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000440 // 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 +0000441 redefineImage(level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000442
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000443 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000444}
445
446void Texture2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
447{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400448 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000449 {
Brandon Jones6518fe22014-07-08 15:16:52 -0700450 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[level]);
Jamie Madill169d1112013-10-24 17:49:37 -0400451 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000452 {
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000453 image->markClean();
454 }
455 }
456}
457
Jamie Madill88f18f42013-09-18 14:36:19 -0400458void 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 +0000459{
Jamie Madill065e1a32013-10-10 15:11:50 -0400460 bool fastUnpacked = false;
461
462 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
463 {
464 rx::RenderTarget *renderTarget = getRenderTarget(level);
465 Box destArea(xoffset, yoffset, 0, width, height, 1);
466
467 if (renderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget))
468 {
469 // Ensure we don't overwrite our newly initialized data
470 mImageArray[level]->markClean();
471
472 fastUnpacked = true;
473 }
474 }
475
476 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000477 {
478 commitRect(level, xoffset, yoffset, width, height);
479 }
480}
481
482void Texture2D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
483{
shannon.woods%transgaming.com@gtempaccount.com4760c562013-04-13 03:42:30 +0000484 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000485 {
486 commitRect(level, xoffset, yoffset, width, height);
487 }
488}
489
490void Texture2D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
491{
Geoff Lange4a492b2014-06-19 14:14:41 -0400492 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
493 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000494 redefineImage(level, sizedInternalFormat, width, height);
shannon.woods@transgaming.com8a406682013-02-28 23:15:26 +0000495
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000496 if (!mImageArray[level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000497 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000498 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000499 mDirtyImages = true;
500 }
501 else
502 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400503 ensureRenderTarget();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000504 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000505
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400506 if (width != 0 && height != 0 && isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000507 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000508 gl::Rectangle sourceRect;
509 sourceRect.x = x;
510 sourceRect.width = width;
511 sourceRect.y = y;
512 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000513
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000514 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000515 }
516 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000517}
518
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +0000519void 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 +0000520{
Jamie Madill07edd442013-07-19 16:36:58 -0400521 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
522 // the current level we're copying to is defined (with appropriate format, width & height)
523 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
524
525 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000526 {
shannon.woods%transgaming.com@gtempaccount.come5dcce72013-04-13 03:44:33 +0000527 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000528 mDirtyImages = true;
529 }
530 else
531 {
Jamie Madille83d1a92013-10-24 17:49:33 -0400532 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000533
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400534 if (isValidLevel(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000535 {
Jamie Madill169d1112013-10-24 17:49:37 -0400536 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -0400537
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +0000538 gl::Rectangle sourceRect;
539 sourceRect.x = x;
540 sourceRect.width = width;
541 sourceRect.y = y;
542 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000543
shannonwoods@chromium.org557aab02013-05-30 00:08:27 +0000544 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -0400545 gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +0000546 xoffset, yoffset, mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000547 }
548 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000549}
550
551void Texture2D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
552{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000553 for (int level = 0; level < levels; level++)
554 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400555 GLsizei levelWidth = std::max(1, width >> level);
556 GLsizei levelHeight = std::max(1, height >> level);
557 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000558 }
559
560 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
561 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +0000562 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000563 }
564
Jamie Madill73b5d062013-10-24 17:49:38 -0400565 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000566
Nicolas Capensbf712d02014-03-31 14:23:35 -0400567 setCompleteTexStorage(new rx::TextureStorageInterface2D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, levels));
Jamie Madill73b5d062013-10-24 17:49:38 -0400568}
569
570void Texture2D::setCompleteTexStorage(rx::TextureStorageInterface2D *newCompleteTexStorage)
571{
572 SafeDelete(mTexStorage);
573 mTexStorage = newCompleteTexStorage;
574
575 if (mTexStorage && mTexStorage->isManaged())
576 {
Nicolas Capensbf712d02014-03-31 14:23:35 -0400577 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000578 {
Brandon Jones6518fe22014-07-08 15:16:52 -0700579 rx::ImageD3D::makeImageD3D(mImageArray[level])->setManagedSurface(mTexStorage, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000580 }
581 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400582
583 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000584}
585
586// Tests for 2D texture sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 85.
Jamie Madillf8989902013-07-19 16:36:58 -0400587bool Texture2D::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000588{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400589 GLsizei width = getBaseLevelWidth();
590 GLsizei height = getBaseLevelHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000591
592 if (width <= 0 || height <= 0)
593 {
594 return false;
595 }
596
Geoff Langc0b9ef42014-07-02 10:02:37 -0400597 // TODO(geofflang): use context's texture caps
598 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000599 {
Jamie Madillf8989902013-07-19 16:36:58 -0400600 if (samplerState.magFilter != GL_NEAREST ||
601 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000602 {
603 return false;
604 }
605 }
606
Geoff Langc0b9ef42014-07-02 10:02:37 -0400607 // TODO(geofflang): use context's extensions
608 bool npotSupport = mRenderer->getRendererExtensions().textureNPOT;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000609
610 if (!npotSupport)
611 {
Jamie Madillf8989902013-07-19 16:36:58 -0400612 if ((samplerState.wrapS != GL_CLAMP_TO_EDGE && !isPow2(width)) ||
613 (samplerState.wrapT != GL_CLAMP_TO_EDGE && !isPow2(height)))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000614 {
615 return false;
616 }
617 }
618
Jamie Madillf8989902013-07-19 16:36:58 -0400619 if (IsMipmapFiltered(samplerState))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000620 {
621 if (!npotSupport)
622 {
623 if (!isPow2(width) || !isPow2(height))
624 {
625 return false;
626 }
627 }
628
629 if (!isMipmapComplete())
630 {
631 return false;
632 }
633 }
634
Geoff Langc82fc412013-07-10 14:43:42 -0400635 // OpenGLES 3.0.2 spec section 3.8.13 states that a texture is not mipmap complete if:
636 // The internalformat specified for the texture arrays is a sized internal depth or
637 // depth and stencil format (see table 3.13), the value of TEXTURE_COMPARE_-
638 // MODE is NONE, and either the magnification filter is not NEAREST or the mini-
639 // fication filter is neither NEAREST nor NEAREST_MIPMAP_NEAREST.
Geoff Lange4a492b2014-06-19 14:14:41 -0400640 if (gl::GetDepthBits(getInternalFormat(0)) > 0 && mRenderer->getCurrentClientVersion() > 2)
Geoff Langc82fc412013-07-10 14:43:42 -0400641 {
642 if (mSamplerState.compareMode == GL_NONE)
643 {
644 if ((mSamplerState.minFilter != GL_NEAREST && mSamplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST) ||
645 mSamplerState.magFilter != GL_NEAREST)
646 {
647 return false;
648 }
649 }
650 }
651
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000652 return true;
653}
654
655// Tests for 2D texture (mipmap) completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
656bool Texture2D::isMipmapComplete() const
657{
Geoff Lang98705b72014-03-31 16:00:03 -0400658 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -0400659
Geoff Lang98705b72014-03-31 16:00:03 -0400660 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -0400661 {
662 if (!isLevelComplete(level))
663 {
664 return false;
665 }
666 }
667
668 return true;
669}
670
671bool Texture2D::isLevelComplete(int level) const
672{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000673 if (isImmutable())
674 {
675 return true;
676 }
677
Jamie Madill648c9682014-01-21 16:50:58 -0500678 const rx::Image *baseImage = getBaseLevelImage();
679
680 GLsizei width = baseImage->getWidth();
681 GLsizei height = baseImage->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000682
683 if (width <= 0 || height <= 0)
684 {
685 return false;
686 }
687
Jamie Madill07edd442013-07-19 16:36:58 -0400688 // The base image level is complete if the width and height are positive
689 if (level == 0)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000690 {
Jamie Madill07edd442013-07-19 16:36:58 -0400691 return true;
692 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000693
Jamie Madill07edd442013-07-19 16:36:58 -0400694 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
695 rx::Image *image = mImageArray[level];
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000696
Jamie Madill648c9682014-01-21 16:50:58 -0500697 if (image->getInternalFormat() != baseImage->getInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -0400698 {
699 return false;
700 }
701
702 if (image->getWidth() != std::max(1, width >> level))
703 {
704 return false;
705 }
706
707 if (image->getHeight() != std::max(1, height >> level))
708 {
709 return false;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000710 }
711
712 return true;
713}
714
715bool Texture2D::isCompressed(GLint level) const
716{
Geoff Lange4a492b2014-06-19 14:14:41 -0400717 return IsFormatCompressed(getInternalFormat(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000718}
719
720bool Texture2D::isDepth(GLint level) const
721{
Geoff Lange4a492b2014-06-19 14:14:41 -0400722 return GetDepthBits(getInternalFormat(level)) > 0;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000723}
724
daniel@transgaming.comf032cb82012-10-31 19:51:52 +0000725// Constructs a native texture resource from the texture images
Jamie Madill73b5d062013-10-24 17:49:38 -0400726void Texture2D::initializeStorage(bool renderTarget)
727{
728 // Only initialize the first time this texture is used as a render target or shader resource
729 if (mTexStorage)
730 {
731 return;
732 }
733
734 // do not attempt to create storage for nonexistant data
735 if (!isLevelComplete(0))
736 {
737 return;
738 }
739
740 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
741
742 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
743 ASSERT(mTexStorage);
744
745 // flush image data to the storage
746 updateStorage();
747}
748
749rx::TextureStorageInterface2D *Texture2D::createCompleteStorage(bool renderTarget) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000750{
Jamie Madilld3d2a342013-10-07 10:46:35 -0400751 GLsizei width = getBaseLevelWidth();
752 GLsizei height = getBaseLevelHeight();
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000753
Jamie Madill73b5d062013-10-24 17:49:38 -0400754 ASSERT(width > 0 && height > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +0000755
Jamie Madill73b5d062013-10-24 17:49:38 -0400756 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -0400757 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000758
Nicolas Capensbf712d02014-03-31 14:23:35 -0400759 return new rx::TextureStorageInterface2D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, levels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000760}
761
Jamie Madill169d1112013-10-24 17:49:37 -0400762void Texture2D::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000763{
Geoff Lang946b9482014-05-12 16:37:25 -0400764 ASSERT(mTexStorage != NULL);
765 GLint storageLevels = mTexStorage->getLevelCount();
766 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000767 {
Jamie Madill648c9682014-01-21 16:50:58 -0500768 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -0400769 {
Jamie Madill169d1112013-10-24 17:49:37 -0400770 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -0400771 }
Jamie Madill07edd442013-07-19 16:36:58 -0400772 }
773}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000774
Jamie Madill169d1112013-10-24 17:49:37 -0400775void Texture2D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -0400776{
777 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -0400778 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -0400779
Jamie Madillaee7ad82013-10-10 16:07:32 -0400780 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -0400781 {
Jamie Madillaee7ad82013-10-10 16:07:32 -0400782 commitRect(level, 0, 0, getWidth(level), getHeight(level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000783 }
784}
785
Jamie Madille83d1a92013-10-24 17:49:33 -0400786bool Texture2D::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000787{
Jamie Madill73b5d062013-10-24 17:49:38 -0400788 initializeStorage(true);
789
790 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -0400791 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400792 ASSERT(mTexStorage);
793 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000794 {
Jamie Madill73b5d062013-10-24 17:49:38 -0400795 rx::TextureStorageInterface2D *newRenderTargetStorage = createCompleteStorage(true);
796
797 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
798 {
799 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -0400800 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000801 }
Jamie Madill73b5d062013-10-24 17:49:38 -0400802
803 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000804 }
805 }
806
Jamie Madille83d1a92013-10-24 17:49:33 -0400807 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000808}
809
810void Texture2D::generateMipmaps()
811{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000812 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -0400813 int levelCount = mipLevels();
814 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000815 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400816 redefineImage(level, getBaseLevelInternalFormat(),
817 std::max(getBaseLevelWidth() >> level, 1),
818 std::max(getBaseLevelHeight() >> level, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000819 }
820
821 if (mTexStorage && mTexStorage->isRenderTarget())
822 {
Geoff Lang98705b72014-03-31 16:00:03 -0400823 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000824 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400825 mTexStorage->generateMipmap(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000826
Jamie Madill22f843a2013-10-24 17:49:36 -0400827 mImageArray[level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000828 }
829 }
830 else
831 {
Geoff Lang98705b72014-03-31 16:00:03 -0400832 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000833 {
Jamie Madill22f843a2013-10-24 17:49:36 -0400834 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000835 }
836 }
837}
838
Jamie Madilld3d2a342013-10-07 10:46:35 -0400839const rx::Image *Texture2D::getBaseLevelImage() const
840{
841 return mImageArray[0];
842}
843
Jamie Madill2ebab852013-10-24 17:49:42 -0400844rx::TextureStorageInterface *Texture2D::getBaseLevelStorage()
845{
846 return mTexStorage;
847}
848
Geoff Lang8040f572013-07-25 16:49:54 -0400849unsigned int Texture2D::getRenderTargetSerial(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000850{
Jamie Madille83d1a92013-10-24 17:49:33 -0400851 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -0400852}
853
854rx::RenderTarget *Texture2D::getRenderTarget(GLint level)
855{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000856 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400857 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000858 {
859 return NULL;
860 }
861
Jamie Madill169d1112013-10-24 17:49:37 -0400862 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -0400863
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000864 // ensure this is NOT a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400865 if (isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000866 {
867 return NULL;
868 }
daniel@transgaming.com34da3972012-12-20 21:10:29 +0000869
Geoff Lang8040f572013-07-25 16:49:54 -0400870 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000871}
872
Geoff Lang8040f572013-07-25 16:49:54 -0400873rx::RenderTarget *Texture2D::getDepthSencil(GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000874{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000875 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -0400876 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000877 {
878 return NULL;
879 }
880
Jamie Madill169d1112013-10-24 17:49:37 -0400881 updateStorageLevel(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000882
883 // ensure this is actually a depth texture
Geoff Lang8040f572013-07-25 16:49:54 -0400884 if (!isDepth(level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000885 {
886 return NULL;
887 }
Geoff Lang8040f572013-07-25 16:49:54 -0400888
889 return mTexStorage->getRenderTarget(level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000890}
891
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400892bool Texture2D::isValidLevel(int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000893{
Nicolas Capensbf712d02014-03-31 14:23:35 -0400894 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +0000895}
896
Geoff Lang4907f2c2013-07-25 12:53:57 -0400897TextureCubeMap::TextureCubeMap(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_CUBE_MAP)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000898{
899 mTexStorage = NULL;
900 for (int i = 0; i < 6; i++)
901 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000902 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
903 {
daniel@transgaming.com244e1832012-12-20 20:52:35 +0000904 mImageArray[i][j] = renderer->createImage();
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000905 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000906 }
907}
908
909TextureCubeMap::~TextureCubeMap()
910{
911 for (int i = 0; i < 6; i++)
912 {
daniel@transgaming.comd9ec9022012-12-20 20:52:16 +0000913 for (int j = 0; j < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
914 {
915 delete mImageArray[i][j];
916 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000917 }
918
919 delete mTexStorage;
920 mTexStorage = NULL;
921}
922
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000923GLsizei TextureCubeMap::getWidth(GLenum target, GLint level) const
924{
925 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400926 return mImageArray[targetToIndex(target)][level]->getWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000927 else
928 return 0;
929}
930
931GLsizei TextureCubeMap::getHeight(GLenum target, GLint level) const
932{
933 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400934 return mImageArray[targetToIndex(target)][level]->getHeight();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000935 else
936 return 0;
937}
938
939GLenum TextureCubeMap::getInternalFormat(GLenum target, GLint level) const
940{
941 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400942 return mImageArray[targetToIndex(target)][level]->getInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000943 else
944 return GL_NONE;
945}
946
daniel@transgaming.com20d36662012-10-31 19:51:43 +0000947GLenum TextureCubeMap::getActualFormat(GLenum target, GLint level) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000948{
949 if (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Jamie Madill2db197c2013-10-24 17:49:35 -0400950 return mImageArray[targetToIndex(target)][level]->getActualFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000951 else
Geoff Langcbf727a2014-02-10 12:50:45 -0500952 return GL_NONE;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000953}
954
Geoff Lang005df412013-10-16 14:12:50 -0400955void 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 +0000956{
Jamie Madill88f18f42013-09-18 14:36:19 -0400957 setImage(0, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000958}
959
Geoff Lang005df412013-10-16 14:12:50 -0400960void 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 +0000961{
Jamie Madill88f18f42013-09-18 14:36:19 -0400962 setImage(1, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000963}
964
Geoff Lang005df412013-10-16 14:12:50 -0400965void 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 +0000966{
Jamie Madill88f18f42013-09-18 14:36:19 -0400967 setImage(2, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000968}
969
Geoff Lang005df412013-10-16 14:12:50 -0400970void 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 +0000971{
Jamie Madill88f18f42013-09-18 14:36:19 -0400972 setImage(3, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000973}
974
Geoff Lang005df412013-10-16 14:12:50 -0400975void 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 +0000976{
Jamie Madill88f18f42013-09-18 14:36:19 -0400977 setImage(4, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000978}
979
Geoff Lang005df412013-10-16 14:12:50 -0400980void 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 +0000981{
Jamie Madill88f18f42013-09-18 14:36:19 -0400982 setImage(5, level, width, height, internalFormat, format, type, unpack, pixels);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000983}
984
Jamie Madill2db197c2013-10-24 17:49:35 -0400985void 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 +0000986{
daniel@transgaming.com6452adf2012-10-17 18:22:35 +0000987 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Jamie Madill2db197c2013-10-24 17:49:35 -0400988 int faceIndex = targetToIndex(target);
989 redefineImage(faceIndex, level, format, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000990
Jamie Madill2db197c2013-10-24 17:49:35 -0400991 Texture::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000992}
993
Jamie Madill2db197c2013-10-24 17:49:35 -0400994void TextureCubeMap::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000995{
Jamie Madill07bb8cf2013-10-24 17:49:44 -0400996 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +0000997 {
Brandon Jones6518fe22014-07-08 15:16:52 -0700998 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[faceIndex][level]);
Jamie Madill169d1112013-10-24 17:49:37 -0400999 if (image->copyToStorage(mTexStorage, faceIndex, level, xoffset, yoffset, width, height))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001000 image->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001001 }
1002}
1003
Jamie Madill88f18f42013-09-18 14:36:19 -04001004void 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 +00001005{
Jamie Madill2db197c2013-10-24 17:49:35 -04001006 int faceIndex = targetToIndex(target);
1007 if (Texture::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001008 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001009 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001010 }
1011}
1012
1013void TextureCubeMap::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels)
1014{
Jamie Madill2db197c2013-10-24 17:49:35 -04001015 int faceIndex = targetToIndex(target);
1016 if (Texture::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001017 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001018 commitRect(faceIndex, level, xoffset, yoffset, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001019 }
1020}
1021
1022// Tests for cube map sampling completeness. [OpenGL ES 2.0.24] section 3.8.2 page 86.
Jamie Madillf8989902013-07-19 16:36:58 -04001023bool TextureCubeMap::isSamplerComplete(const SamplerState &samplerState) const
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001024{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001025 int size = getBaseLevelWidth();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001026
Jamie Madillf8989902013-07-19 16:36:58 -04001027 bool mipmapping = IsMipmapFiltered(samplerState);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001028
Geoff Langc0b9ef42014-07-02 10:02:37 -04001029 // TODO(geofflang): use context's texture caps
1030 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0)).filtering)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001031 {
Jamie Madillf8989902013-07-19 16:36:58 -04001032 if (samplerState.magFilter != GL_NEAREST ||
1033 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001034 {
1035 return false;
1036 }
1037 }
1038
Geoff Langc0b9ef42014-07-02 10:02:37 -04001039 // TODO(geofflang): use context's extensions
1040 if (!isPow2(size) && !mRenderer->getRendererExtensions().textureNPOT)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001041 {
Jamie Madillf8989902013-07-19 16:36:58 -04001042 if (samplerState.wrapS != GL_CLAMP_TO_EDGE || samplerState.wrapT != GL_CLAMP_TO_EDGE || mipmapping)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001043 {
1044 return false;
1045 }
1046 }
1047
1048 if (!mipmapping)
1049 {
1050 if (!isCubeComplete())
1051 {
1052 return false;
1053 }
1054 }
1055 else
1056 {
1057 if (!isMipmapCubeComplete()) // Also tests for isCubeComplete()
1058 {
1059 return false;
1060 }
1061 }
1062
1063 return true;
1064}
1065
1066// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1067bool TextureCubeMap::isCubeComplete() const
1068{
Jamie Madillc1f8b162013-10-07 10:46:38 -04001069 int baseWidth = getBaseLevelWidth();
1070 int baseHeight = getBaseLevelHeight();
1071 GLenum baseFormat = getBaseLevelInternalFormat();
1072
1073 if (baseWidth <= 0 || baseWidth != baseHeight)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001074 {
1075 return false;
1076 }
1077
Jamie Madill2db197c2013-10-24 17:49:35 -04001078 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001079 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001080 const rx::Image &faceBaseImage = *mImageArray[faceIndex][0];
Jamie Madillc1f8b162013-10-07 10:46:38 -04001081
1082 if (faceBaseImage.getWidth() != baseWidth ||
1083 faceBaseImage.getHeight() != baseHeight ||
1084 faceBaseImage.getInternalFormat() != baseFormat )
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001085 {
1086 return false;
1087 }
1088 }
1089
1090 return true;
1091}
1092
1093bool TextureCubeMap::isMipmapCubeComplete() const
1094{
1095 if (isImmutable())
1096 {
1097 return true;
1098 }
1099
1100 if (!isCubeComplete())
1101 {
1102 return false;
1103 }
1104
Geoff Lang98705b72014-03-31 16:00:03 -04001105 int levelCount = mipLevels();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001106
1107 for (int face = 0; face < 6; face++)
1108 {
Geoff Lang98705b72014-03-31 16:00:03 -04001109 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001110 {
Jamie Madill07edd442013-07-19 16:36:58 -04001111 if (!isFaceLevelComplete(face, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001112 {
1113 return false;
1114 }
1115 }
1116 }
1117
1118 return true;
1119}
1120
Jamie Madill2db197c2013-10-24 17:49:35 -04001121bool TextureCubeMap::isFaceLevelComplete(int faceIndex, int level) const
Jamie Madill07edd442013-07-19 16:36:58 -04001122{
Jamie Madill2db197c2013-10-24 17:49:35 -04001123 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
Jamie Madill07edd442013-07-19 16:36:58 -04001124
1125 if (isImmutable())
1126 {
1127 return true;
1128 }
1129
Jamie Madilld3d2a342013-10-07 10:46:35 -04001130 int baseSize = getBaseLevelWidth();
Jamie Madill07edd442013-07-19 16:36:58 -04001131
Jamie Madilld3d2a342013-10-07 10:46:35 -04001132 if (baseSize <= 0)
Jamie Madill07edd442013-07-19 16:36:58 -04001133 {
1134 return false;
1135 }
1136
Jamie Madilld3d2a342013-10-07 10:46:35 -04001137 // "isCubeComplete" checks for base level completeness and we must call that
1138 // to determine if any face at level 0 is complete. We omit that check here
1139 // to avoid re-checking cube-completeness for every face at level 0.
Jamie Madill07edd442013-07-19 16:36:58 -04001140 if (level == 0)
1141 {
1142 return true;
1143 }
1144
Jamie Madilld3d2a342013-10-07 10:46:35 -04001145 // Check that non-zero levels are consistent with the base level.
Jamie Madill2db197c2013-10-24 17:49:35 -04001146 const rx::Image *faceLevelImage = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001147
Jamie Madilld3d2a342013-10-07 10:46:35 -04001148 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001149 {
1150 return false;
1151 }
1152
Jamie Madilld3d2a342013-10-07 10:46:35 -04001153 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
Jamie Madill07edd442013-07-19 16:36:58 -04001154 {
1155 return false;
1156 }
1157
1158 return true;
1159}
1160
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001161bool TextureCubeMap::isCompressed(GLenum target, GLint level) const
1162{
Geoff Lange4a492b2014-06-19 14:14:41 -04001163 return IsFormatCompressed(getInternalFormat(target, level));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001164}
1165
Geoff Lang8040f572013-07-25 16:49:54 -04001166bool TextureCubeMap::isDepth(GLenum target, GLint level) const
1167{
Geoff Lange4a492b2014-06-19 14:14:41 -04001168 return GetDepthBits(getInternalFormat(target, level)) > 0;
Geoff Lang8040f572013-07-25 16:49:54 -04001169}
1170
Jamie Madill73b5d062013-10-24 17:49:38 -04001171void TextureCubeMap::initializeStorage(bool renderTarget)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001172{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001173 // Only initialize the first time this texture is used as a render target or shader resource
1174 if (mTexStorage)
1175 {
1176 return;
1177 }
1178
1179 // do not attempt to create storage for nonexistant data
1180 if (!isFaceLevelComplete(0, 0))
1181 {
1182 return;
1183 }
1184
1185 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1186
1187 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1188 ASSERT(mTexStorage);
1189
1190 // flush image data to the storage
1191 updateStorage();
1192}
1193
1194rx::TextureStorageInterfaceCube *TextureCubeMap::createCompleteStorage(bool renderTarget) const
1195{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001196 GLsizei size = getBaseLevelWidth();
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001197
Jamie Madill3c0989c2013-10-24 17:49:39 -04001198 ASSERT(size > 0);
daniel@transgaming.come6a09842012-09-17 21:28:55 +00001199
Jamie Madill3c0989c2013-10-24 17:49:39 -04001200 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001201 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001202
Nicolas Capensbf712d02014-03-31 14:23:35 -04001203 return new rx::TextureStorageInterfaceCube(mRenderer, getBaseLevelInternalFormat(), renderTarget, size, levels);
Jamie Madill3c0989c2013-10-24 17:49:39 -04001204}
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001205
Jamie Madill3c0989c2013-10-24 17:49:39 -04001206void TextureCubeMap::setCompleteTexStorage(rx::TextureStorageInterfaceCube *newCompleteTexStorage)
1207{
1208 SafeDelete(mTexStorage);
1209 mTexStorage = newCompleteTexStorage;
1210
1211 if (mTexStorage && mTexStorage->isManaged())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001212 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001213 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001214 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001215 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001216 {
Brandon Jones6518fe22014-07-08 15:16:52 -07001217 rx::ImageD3D::makeImageD3D(mImageArray[faceIndex][level])->setManagedSurface(mTexStorage, faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001218 }
1219 }
1220 }
1221
1222 mDirtyImages = true;
1223}
1224
Jamie Madill169d1112013-10-24 17:49:37 -04001225void TextureCubeMap::updateStorage()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001226{
Geoff Lang946b9482014-05-12 16:37:25 -04001227 ASSERT(mTexStorage != NULL);
1228 GLint storageLevels = mTexStorage->getLevelCount();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001229 for (int face = 0; face < 6; face++)
1230 {
Geoff Lang946b9482014-05-12 16:37:25 -04001231 for (int level = 0; level < storageLevels; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001232 {
Geoff Lang946b9482014-05-12 16:37:25 -04001233 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001234 {
Jamie Madill169d1112013-10-24 17:49:37 -04001235 updateStorageFaceLevel(face, level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001236 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001237 }
1238 }
1239}
1240
Jamie Madill169d1112013-10-24 17:49:37 -04001241void TextureCubeMap::updateStorageFaceLevel(int faceIndex, int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001242{
Jamie Madill2db197c2013-10-24 17:49:35 -04001243 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1244 rx::Image *image = mImageArray[faceIndex][level];
Jamie Madill07edd442013-07-19 16:36:58 -04001245
1246 if (image->isDirty())
1247 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001248 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
Jamie Madill07edd442013-07-19 16:36:58 -04001249 }
1250}
1251
Jamie Madille83d1a92013-10-24 17:49:33 -04001252bool TextureCubeMap::ensureRenderTarget()
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001253{
Jamie Madill3c0989c2013-10-24 17:49:39 -04001254 initializeStorage(true);
1255
1256 if (getBaseLevelWidth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001257 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001258 ASSERT(mTexStorage);
1259 if (!mTexStorage->isRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001260 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001261 rx::TextureStorageInterfaceCube *newRenderTargetStorage = createCompleteStorage(true);
1262
1263 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001264 {
Jamie Madill3c0989c2013-10-24 17:49:39 -04001265 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001266 return gl::error(GL_OUT_OF_MEMORY, false);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001267 }
Jamie Madill3c0989c2013-10-24 17:49:39 -04001268
1269 setCompleteTexStorage(newRenderTargetStorage);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001270 }
1271 }
1272
Jamie Madille83d1a92013-10-24 17:49:33 -04001273 return (mTexStorage && mTexStorage->isRenderTarget());
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001274}
1275
Geoff Lang005df412013-10-16 14:12:50 -04001276void 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 +00001277{
Geoff Lange4a492b2014-06-19 14:14:41 -04001278 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1279 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001280
1281 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001282
Jamie Madill88f18f42013-09-18 14:36:19 -04001283 Texture::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001284}
1285
Jamie Madill2db197c2013-10-24 17:49:35 -04001286int TextureCubeMap::targetToIndex(GLenum target)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001287{
1288 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1);
1289 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2);
1290 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3);
1291 META_ASSERT(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4);
1292 META_ASSERT(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5);
1293
Jamie Madill2db197c2013-10-24 17:49:35 -04001294 return target - GL_TEXTURE_CUBE_MAP_POSITIVE_X;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001295}
1296
Jamie Madill2db197c2013-10-24 17:49:35 -04001297void TextureCubeMap::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001298{
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001299 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001300 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1301 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04001302 const GLenum storageFormat = getBaseLevelInternalFormat();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001303
Jamie Madill2db197c2013-10-24 17:49:35 -04001304 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001305
1306 if (mTexStorage)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001307 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04001308 const int storageLevels = mTexStorage->getLevelCount();
1309
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001310 if ((level >= storageLevels && storageLevels != 0) ||
1311 width != storageWidth ||
1312 height != storageHeight ||
1313 internalformat != storageFormat) // Discard mismatched storage
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001314 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001315 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001316 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001317 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001318 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001319 mImageArray[faceIndex][level]->markDirty();
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001320 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001321 }
shannon.woods@transgaming.come2e97982013-02-28 23:18:50 +00001322
1323 delete mTexStorage;
1324 mTexStorage = NULL;
1325
1326 mDirtyImages = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001327 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001328 }
1329}
1330
1331void TextureCubeMap::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1332{
Jamie Madill2db197c2013-10-24 17:49:35 -04001333 int faceIndex = targetToIndex(target);
Geoff Lange4a492b2014-06-19 14:14:41 -04001334 GLenum sizedInternalFormat = IsSizedInternalFormat(format) ? format
1335 : GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
Jamie Madill2db197c2013-10-24 17:49:35 -04001336 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001337
Jamie Madill2db197c2013-10-24 17:49:35 -04001338 if (!mImageArray[faceIndex][level]->isRenderableFormat())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001339 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001340 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001341 mDirtyImages = true;
1342 }
1343 else
1344 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001345 ensureRenderTarget();
Jamie Madill2db197c2013-10-24 17:49:35 -04001346 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001347
1348 ASSERT(width == height);
1349
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001350 if (width > 0 && isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001351 {
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001352 gl::Rectangle sourceRect;
1353 sourceRect.x = x;
1354 sourceRect.width = width;
1355 sourceRect.y = y;
1356 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001357
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001358 mRenderer->copyImage(source, sourceRect, format, 0, 0, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001359 }
1360 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001361}
1362
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001363void 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 +00001364{
Jamie Madill2db197c2013-10-24 17:49:35 -04001365 int faceIndex = targetToIndex(target);
1366
Jamie Madilld3d2a342013-10-07 10:46:35 -04001367 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1368 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1369 // rely on the "getBaseLevel*" methods reliably otherwise.
Jamie Madill2db197c2013-10-24 17:49:35 -04001370 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
Jamie Madill07edd442013-07-19 16:36:58 -04001371
Jamie Madill2db197c2013-10-24 17:49:35 -04001372 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001373 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001374 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001375 mDirtyImages = true;
1376 }
1377 else
1378 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001379 ensureRenderTarget();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001380
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001381 if (isValidFaceLevel(faceIndex, level))
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001382 {
Jamie Madill169d1112013-10-24 17:49:37 -04001383 updateStorageFaceLevel(faceIndex, level);
Jamie Madill07edd442013-07-19 16:36:58 -04001384
shannon.woods@transgaming.com664916b2013-01-25 21:50:32 +00001385 gl::Rectangle sourceRect;
1386 sourceRect.x = x;
1387 sourceRect.width = width;
1388 sourceRect.y = y;
1389 sourceRect.height = height;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001390
Geoff Lange4a492b2014-06-19 14:14:41 -04001391 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getBaseLevelInternalFormat()),
daniel@transgaming.comde8a7ff2012-11-28 19:34:13 +00001392 xoffset, yoffset, mTexStorage, target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001393 }
1394 }
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001395}
1396
1397void TextureCubeMap::storage(GLsizei levels, GLenum internalformat, GLsizei size)
1398{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001399 for (int level = 0; level < levels; level++)
1400 {
Geoff Langd3110192013-09-24 11:52:47 -04001401 GLsizei mipSize = std::max(1, size >> level);
Jamie Madill2db197c2013-10-24 17:49:35 -04001402 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001403 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001404 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001405 }
1406 }
1407
1408 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1409 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001410 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001411 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001412 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001413 }
1414 }
1415
Jamie Madill3c0989c2013-10-24 17:49:39 -04001416 mImmutable = true;
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001417
Nicolas Capensbf712d02014-03-31 14:23:35 -04001418 setCompleteTexStorage(new rx::TextureStorageInterfaceCube(mRenderer, internalformat, IsRenderTargetUsage(mUsage), size, levels));
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001419}
1420
1421void TextureCubeMap::generateMipmaps()
1422{
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001423 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001424 int levelCount = mipLevels();
Jamie Madill2db197c2013-10-24 17:49:35 -04001425 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001426 {
Geoff Lang98705b72014-03-31 16:00:03 -04001427 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001428 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001429 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1430 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001431 }
1432 }
1433
1434 if (mTexStorage && mTexStorage->isRenderTarget())
1435 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001436 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001437 {
Geoff Lang98705b72014-03-31 16:00:03 -04001438 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001439 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001440 mTexStorage->generateMipmap(faceIndex, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001441
Jamie Madill2db197c2013-10-24 17:49:35 -04001442 mImageArray[faceIndex][level]->markClean();
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001443 }
1444 }
1445 }
1446 else
1447 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001448 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001449 {
Geoff Lang98705b72014-03-31 16:00:03 -04001450 for (int level = 1; level < levelCount; level++)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001451 {
Jamie Madill2db197c2013-10-24 17:49:35 -04001452 mRenderer->generateMipmap(mImageArray[faceIndex][level], mImageArray[faceIndex][level - 1]);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001453 }
1454 }
1455 }
1456}
1457
Jamie Madilld3d2a342013-10-07 10:46:35 -04001458const rx::Image *TextureCubeMap::getBaseLevelImage() const
1459{
1460 // Note: if we are not cube-complete, there is no single base level image that can describe all
1461 // cube faces, so this method is only well-defined for a cube-complete base level.
1462 return mImageArray[0][0];
1463}
1464
Jamie Madill2ebab852013-10-24 17:49:42 -04001465rx::TextureStorageInterface *TextureCubeMap::getBaseLevelStorage()
1466{
1467 return mTexStorage;
1468}
1469
Jamie Madill2db197c2013-10-24 17:49:35 -04001470unsigned int TextureCubeMap::getRenderTargetSerial(GLenum target, GLint level)
Geoff Lang8040f572013-07-25 16:49:54 -04001471{
Jamie Madill2db197c2013-10-24 17:49:35 -04001472 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(target, level) : 0);
Geoff Lang8040f572013-07-25 16:49:54 -04001473}
1474
1475rx::RenderTarget *TextureCubeMap::getRenderTarget(GLenum target, GLint level)
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001476{
1477 ASSERT(IsCubemapTextureTarget(target));
1478
1479 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001480 if (!ensureRenderTarget())
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001481 {
1482 return NULL;
1483 }
1484
Jamie Madill169d1112013-10-24 17:49:37 -04001485 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001486
1487 // ensure this is NOT a depth texture
1488 if (isDepth(target, level))
1489 {
1490 return NULL;
1491 }
1492
1493 return mTexStorage->getRenderTarget(target, level);
1494}
1495
1496rx::RenderTarget *TextureCubeMap::getDepthStencil(GLenum target, GLint level)
1497{
1498 ASSERT(IsCubemapTextureTarget(target));
1499
1500 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001501 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001502 {
1503 return NULL;
1504 }
1505
Jamie Madill169d1112013-10-24 17:49:37 -04001506 updateStorageFaceLevel(targetToIndex(target), level);
Geoff Lang8040f572013-07-25 16:49:54 -04001507
1508 // ensure this is a depth texture
1509 if (!isDepth(target, level))
1510 {
1511 return NULL;
1512 }
1513
1514 return mTexStorage->getRenderTarget(target, level);
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00001515}
1516
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001517bool TextureCubeMap::isValidFaceLevel(int faceIndex, int level) const
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001518{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001519 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
daniel@transgaming.com690d8ae2012-10-31 19:52:08 +00001520}
1521
Geoff Lang4907f2c2013-07-25 12:53:57 -04001522Texture3D::Texture3D(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_3D)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001523{
1524 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001525
1526 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1527 {
1528 mImageArray[i] = renderer->createImage();
1529 }
1530}
1531
1532Texture3D::~Texture3D()
1533{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001534 delete mTexStorage;
1535 mTexStorage = NULL;
1536
1537 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1538 {
1539 delete mImageArray[i];
1540 }
1541}
1542
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001543GLsizei Texture3D::getWidth(GLint level) const
1544{
1545 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getWidth() : 0;
1546}
1547
1548GLsizei Texture3D::getHeight(GLint level) const
1549{
1550 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getHeight() : 0;
1551}
1552
1553GLsizei Texture3D::getDepth(GLint level) const
1554{
1555 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getDepth() : 0;
1556}
1557
1558GLenum Texture3D::getInternalFormat(GLint level) const
1559{
1560 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getInternalFormat() : GL_NONE;
1561}
1562
1563GLenum Texture3D::getActualFormat(GLint level) const
1564{
Geoff Langcbf727a2014-02-10 12:50:45 -05001565 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mImageArray[level]->getActualFormat() : GL_NONE;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001566}
1567
1568bool Texture3D::isCompressed(GLint level) const
1569{
Geoff Lange4a492b2014-06-19 14:14:41 -04001570 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001571}
1572
1573bool Texture3D::isDepth(GLint level) const
1574{
Geoff Lange4a492b2014-06-19 14:14:41 -04001575 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001576}
1577
Geoff Lang005df412013-10-16 14:12:50 -04001578void 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 +00001579{
Geoff Lange4a492b2014-06-19 14:14:41 -04001580 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
1581 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00001582 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001583
Jamie Madilla2d4e552013-10-10 15:12:01 -04001584 bool fastUnpacked = false;
1585
1586 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1587 if (isFastUnpackable(unpack, sizedInternalFormat))
1588 {
1589 // Will try to create RT storage if it does not exist
1590 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1591 Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1592
1593 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget))
1594 {
1595 // Ensure we don't overwrite our newly initialized data
1596 mImageArray[level]->markClean();
1597
1598 fastUnpacked = true;
1599 }
1600 }
1601
1602 if (!fastUnpacked)
1603 {
1604 Texture::setImage(unpack, type, pixels, mImageArray[level]);
1605 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001606}
1607
1608void Texture3D::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
1609{
1610 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1611 redefineImage(level, format, width, height, depth);
1612
1613 Texture::setCompressedImage(imageSize, pixels, mImageArray[level]);
1614}
1615
Jamie Madill88f18f42013-09-18 14:36:19 -04001616void 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 +00001617{
Jamie Madillba4f10a2013-10-10 15:12:20 -04001618 bool fastUnpacked = false;
1619
1620 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1621 if (isFastUnpackable(unpack, getInternalFormat(level)))
1622 {
1623 rx::RenderTarget *destRenderTarget = getRenderTarget(level);
1624 Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1625
1626 if (destRenderTarget && fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget))
1627 {
1628 // Ensure we don't overwrite our newly initialized data
1629 mImageArray[level]->markClean();
1630
1631 fastUnpacked = true;
1632 }
1633 }
1634
1635 if (!fastUnpacked && Texture::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack, pixels, mImageArray[level]))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001636 {
1637 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1638 }
1639}
1640
1641void Texture3D::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
1642{
1643 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth, format, imageSize, pixels, mImageArray[level]))
1644 {
1645 commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1646 }
1647}
1648
1649void Texture3D::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1650{
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001651 for (int level = 0; level < levels; level++)
1652 {
Jamie Madille664e202013-10-24 17:49:40 -04001653 GLsizei levelWidth = std::max(1, width >> level);
1654 GLsizei levelHeight = std::max(1, height >> level);
1655 GLsizei levelDepth = std::max(1, depth >> level);
1656 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001657 }
1658
1659 for (int level = levels; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1660 {
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00001661 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001662 }
1663
Jamie Madille664e202013-10-24 17:49:40 -04001664 mImmutable = true;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001665
Nicolas Capensbf712d02014-03-31 14:23:35 -04001666 setCompleteTexStorage(new rx::TextureStorageInterface3D(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001667}
1668
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001669void Texture3D::generateMipmaps()
1670{
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001671 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04001672 int levelCount = mipLevels();
1673 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001674 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001675 redefineImage(level, getBaseLevelInternalFormat(),
1676 std::max(getBaseLevelWidth() >> level, 1),
1677 std::max(getBaseLevelHeight() >> level, 1),
1678 std::max(getBaseLevelDepth() >> level, 1));
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001679 }
1680
1681 if (mTexStorage && mTexStorage->isRenderTarget())
1682 {
Geoff Lang98705b72014-03-31 16:00:03 -04001683 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001684 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001685 mTexStorage->generateMipmap(level);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001686
Jamie Madill22f843a2013-10-24 17:49:36 -04001687 mImageArray[level]->markClean();
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001688 }
1689 }
1690 else
1691 {
Geoff Lang98705b72014-03-31 16:00:03 -04001692 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001693 {
Jamie Madill22f843a2013-10-24 17:49:36 -04001694 mRenderer->generateMipmap(mImageArray[level], mImageArray[level - 1]);
shannonwoods@chromium.org37b8a912013-05-30 00:04:21 +00001695 }
1696 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001697}
1698
Jamie Madilld3d2a342013-10-07 10:46:35 -04001699const rx::Image *Texture3D::getBaseLevelImage() const
1700{
1701 return mImageArray[0];
1702}
1703
Jamie Madill2ebab852013-10-24 17:49:42 -04001704rx::TextureStorageInterface *Texture3D::getBaseLevelStorage()
1705{
1706 return mTexStorage;
1707}
1708
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001709void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
1710{
Jamie Madill07edd442013-07-19 16:36:58 -04001711 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1712 // the current level we're copying to is defined (with appropriate format, width & height)
1713 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1714
1715 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001716 {
1717 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1718 mDirtyImages = true;
1719 }
1720 else
1721 {
Jamie Madille83d1a92013-10-24 17:49:33 -04001722 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001723
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001724 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001725 {
Jamie Madill169d1112013-10-24 17:49:37 -04001726 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04001727
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001728 gl::Rectangle sourceRect;
1729 sourceRect.x = x;
1730 sourceRect.width = width;
1731 sourceRect.y = y;
1732 sourceRect.height = height;
1733
1734 mRenderer->copyImage(source, sourceRect,
Geoff Lange4a492b2014-06-19 14:14:41 -04001735 gl::GetFormat(getBaseLevelInternalFormat()),
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001736 xoffset, yoffset, zoffset, mTexStorage, level);
1737 }
1738 }
1739}
1740
Jamie Madillf8989902013-07-19 16:36:58 -04001741bool Texture3D::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001742{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001743 GLsizei width = getBaseLevelWidth();
1744 GLsizei height = getBaseLevelHeight();
1745 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001746
1747 if (width <= 0 || height <= 0 || depth <= 0)
1748 {
1749 return false;
1750 }
1751
Geoff Langc0b9ef42014-07-02 10:02:37 -04001752 // TODO(geofflang): use context's texture caps
1753 if (!mRenderer->getRendererTextureCaps().get(getInternalFormat(0)).filtering)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001754 {
Jamie Madillf8989902013-07-19 16:36:58 -04001755 if (samplerState.magFilter != GL_NEAREST ||
1756 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001757 {
1758 return false;
1759 }
1760 }
1761
Jamie Madillf8989902013-07-19 16:36:58 -04001762 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001763 {
1764 return false;
1765 }
1766
1767 return true;
1768}
1769
1770bool Texture3D::isMipmapComplete() const
1771{
Geoff Lang98705b72014-03-31 16:00:03 -04001772 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04001773
Geoff Lang98705b72014-03-31 16:00:03 -04001774 for (int level = 0; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04001775 {
1776 if (!isLevelComplete(level))
1777 {
1778 return false;
1779 }
1780 }
1781
1782 return true;
1783}
1784
1785bool Texture3D::isLevelComplete(int level) const
1786{
1787 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1788
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001789 if (isImmutable())
1790 {
1791 return true;
1792 }
1793
Jamie Madilld3d2a342013-10-07 10:46:35 -04001794 GLsizei width = getBaseLevelWidth();
1795 GLsizei height = getBaseLevelHeight();
1796 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001797
1798 if (width <= 0 || height <= 0 || depth <= 0)
1799 {
1800 return false;
1801 }
1802
Jamie Madill07edd442013-07-19 16:36:58 -04001803 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001804 {
Jamie Madill07edd442013-07-19 16:36:58 -04001805 return true;
1806 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001807
Jamie Madill07edd442013-07-19 16:36:58 -04001808 rx::Image *levelImage = mImageArray[level];
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001809
Jamie Madilld3d2a342013-10-07 10:46:35 -04001810 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
Jamie Madill07edd442013-07-19 16:36:58 -04001811 {
1812 return false;
1813 }
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001814
Jamie Madill07edd442013-07-19 16:36:58 -04001815 if (levelImage->getWidth() != std::max(1, width >> level))
1816 {
1817 return false;
1818 }
1819
1820 if (levelImage->getHeight() != std::max(1, height >> level))
1821 {
1822 return false;
1823 }
1824
1825 if (levelImage->getDepth() != std::max(1, depth >> level))
1826 {
1827 return false;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001828 }
1829
1830 return true;
1831}
1832
Geoff Lang8040f572013-07-25 16:49:54 -04001833unsigned int Texture3D::getRenderTargetSerial(GLint level, GLint layer)
1834{
Jamie Madille83d1a92013-10-24 17:49:33 -04001835 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001836}
1837
Jamie Madill07bb8cf2013-10-24 17:49:44 -04001838bool Texture3D::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001839{
Nicolas Capensbf712d02014-03-31 14:23:35 -04001840 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001841}
1842
Jamie Madill73b5d062013-10-24 17:49:38 -04001843void Texture3D::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001844{
Jamie Madille664e202013-10-24 17:49:40 -04001845 // Only initialize the first time this texture is used as a render target or shader resource
1846 if (mTexStorage)
1847 {
1848 return;
1849 }
1850
1851 // do not attempt to create storage for nonexistant data
1852 if (!isLevelComplete(0))
1853 {
1854 return;
1855 }
1856
1857 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1858
1859 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1860 ASSERT(mTexStorage);
1861
1862 // flush image data to the storage
1863 updateStorage();
1864}
1865
1866rx::TextureStorageInterface3D *Texture3D::createCompleteStorage(bool renderTarget) const
1867{
Jamie Madilld3d2a342013-10-07 10:46:35 -04001868 GLsizei width = getBaseLevelWidth();
1869 GLsizei height = getBaseLevelHeight();
1870 GLsizei depth = getBaseLevelDepth();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001871
Jamie Madille664e202013-10-24 17:49:40 -04001872 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001873
Jamie Madille664e202013-10-24 17:49:40 -04001874 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04001875 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001876
Nicolas Capensbf712d02014-03-31 14:23:35 -04001877 return new rx::TextureStorageInterface3D(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madille664e202013-10-24 17:49:40 -04001878}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001879
Jamie Madille664e202013-10-24 17:49:40 -04001880void Texture3D::setCompleteTexStorage(rx::TextureStorageInterface3D *newCompleteTexStorage)
1881{
1882 SafeDelete(mTexStorage);
1883 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001884 mDirtyImages = true;
Jamie Madille664e202013-10-24 17:49:40 -04001885
1886 // We do not support managed 3D storage, as that is D3D9/ES2-only
1887 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001888}
1889
Jamie Madill169d1112013-10-24 17:49:37 -04001890void Texture3D::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001891{
Geoff Lang946b9482014-05-12 16:37:25 -04001892 ASSERT(mTexStorage != NULL);
1893 GLint storageLevels = mTexStorage->getLevelCount();
1894 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001895 {
Geoff Lang946b9482014-05-12 16:37:25 -04001896 if (mImageArray[level]->isDirty() && isLevelComplete(level))
Jamie Madilld9b9a502013-10-10 17:46:13 -04001897 {
Jamie Madill169d1112013-10-24 17:49:37 -04001898 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04001899 }
Jamie Madill07edd442013-07-19 16:36:58 -04001900 }
1901}
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001902
Jamie Madill169d1112013-10-24 17:49:37 -04001903void Texture3D::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04001904{
1905 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Jamie Madillaee7ad82013-10-10 16:07:32 -04001906 ASSERT(isLevelComplete(level));
Jamie Madill07edd442013-07-19 16:36:58 -04001907
Jamie Madillaee7ad82013-10-10 16:07:32 -04001908 if (mImageArray[level]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04001909 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04001910 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001911 }
1912}
1913
Jamie Madille83d1a92013-10-24 17:49:33 -04001914bool Texture3D::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001915{
Jamie Madille664e202013-10-24 17:49:40 -04001916 initializeStorage(true);
1917
1918 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04001919 {
Jamie Madille664e202013-10-24 17:49:40 -04001920 ASSERT(mTexStorage);
1921 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001922 {
Jamie Madille664e202013-10-24 17:49:40 -04001923 rx::TextureStorageInterface3D *newRenderTargetStorage = createCompleteStorage(true);
1924
1925 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001926 {
Jamie Madille664e202013-10-24 17:49:40 -04001927 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04001928 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001929 }
Jamie Madille664e202013-10-24 17:49:40 -04001930
1931 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001932 }
1933 }
1934
Jamie Madille83d1a92013-10-24 17:49:33 -04001935 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001936}
1937
Jamie Madilla2d4e552013-10-10 15:12:01 -04001938rx::RenderTarget *Texture3D::getRenderTarget(GLint level)
1939{
1940 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001941 if (!ensureRenderTarget())
Jamie Madilla2d4e552013-10-10 15:12:01 -04001942 {
1943 return NULL;
1944 }
1945
Jamie Madill169d1112013-10-24 17:49:37 -04001946 updateStorageLevel(level);
Jamie Madilla2d4e552013-10-10 15:12:01 -04001947
1948 // ensure this is NOT a depth texture
1949 if (isDepth(level))
1950 {
1951 return NULL;
1952 }
1953
1954 return mTexStorage->getRenderTarget(level);
1955}
1956
Geoff Lang8040f572013-07-25 16:49:54 -04001957rx::RenderTarget *Texture3D::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001958{
Geoff Lang8040f572013-07-25 16:49:54 -04001959 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001960 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001961 {
1962 return NULL;
1963 }
1964
Jamie Madill169d1112013-10-24 17:49:37 -04001965 updateStorage();
Geoff Lang8040f572013-07-25 16:49:54 -04001966
1967 // ensure this is NOT a depth texture
1968 if (isDepth(level))
1969 {
1970 return NULL;
1971 }
1972
1973 return mTexStorage->getRenderTarget(level, layer);
1974}
1975
1976rx::RenderTarget *Texture3D::getDepthStencil(GLint level, GLint layer)
1977{
1978 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04001979 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04001980 {
1981 return NULL;
1982 }
1983
Jamie Madill169d1112013-10-24 17:49:37 -04001984 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04001985
1986 // ensure this is a depth texture
1987 if (!isDepth(level))
1988 {
1989 return NULL;
1990 }
1991
1992 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001993}
1994
Geoff Lang005df412013-10-16 14:12:50 -04001995void Texture3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00001996{
1997 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04001998 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1999 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2000 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
Geoff Lang005df412013-10-16 14:12:50 -04002001 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002002
shannon.woods%transgaming.com@gtempaccount.com56074f32013-04-13 03:45:30 +00002003 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002004
2005 if (mTexStorage)
2006 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002007 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002008
2009 if ((level >= storageLevels && storageLevels != 0) ||
2010 width != storageWidth ||
2011 height != storageHeight ||
2012 depth != storageDepth ||
2013 internalformat != storageFormat) // Discard mismatched storage
2014 {
2015 for (int i = 0; i < IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2016 {
2017 mImageArray[i]->markDirty();
2018 }
2019
2020 delete mTexStorage;
2021 mTexStorage = NULL;
2022 mDirtyImages = true;
2023 }
2024 }
2025}
2026
2027void Texture3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
2028{
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002029 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002030 {
Brandon Jones6518fe22014-07-08 15:16:52 -07002031 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[level]);
Jamie Madill169d1112013-10-24 17:49:37 -04002032 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth))
shannon.woods%transgaming.com@gtempaccount.com95996562013-04-13 03:44:58 +00002033 {
2034 image->markClean();
2035 }
2036 }
2037}
2038
Geoff Lang4907f2c2013-07-25 12:53:57 -04002039Texture2DArray::Texture2DArray(rx::Renderer *renderer, GLuint id) : Texture(renderer, id, GL_TEXTURE_2D_ARRAY)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002040{
2041 mTexStorage = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002042
2043 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2044 {
2045 mLayerCounts[level] = 0;
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002046 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002047 }
2048}
2049
2050Texture2DArray::~Texture2DArray()
2051{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002052 delete mTexStorage;
2053 mTexStorage = NULL;
Jamie Madill884a4622013-10-24 17:49:41 -04002054
2055 deleteImages();
2056}
2057
2058void Texture2DArray::deleteImages()
2059{
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002060 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2061 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002062 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002063 {
2064 delete mImageArray[level][layer];
2065 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002066 delete[] mImageArray[level];
Jamie Madill884a4622013-10-24 17:49:41 -04002067 mImageArray[level] = NULL;
2068 mLayerCounts[level] = 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002069 }
2070}
2071
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002072GLsizei Texture2DArray::getWidth(GLint level) const
2073{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002074 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 +00002075}
2076
2077GLsizei Texture2DArray::getHeight(GLint level) const
2078{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002079 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 +00002080}
2081
Jamie Madillb8f8b892014-01-07 10:12:50 -05002082GLsizei Texture2DArray::getLayers(GLint level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002083{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002084 return (level < IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mLayerCounts[level] : 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002085}
2086
2087GLenum Texture2DArray::getInternalFormat(GLint level) const
2088{
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002089 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 +00002090}
2091
2092GLenum Texture2DArray::getActualFormat(GLint level) const
2093{
Geoff Langcbf727a2014-02-10 12:50:45 -05002094 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 +00002095}
2096
2097bool Texture2DArray::isCompressed(GLint level) const
2098{
Geoff Lange4a492b2014-06-19 14:14:41 -04002099 return IsFormatCompressed(getInternalFormat(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002100}
2101
2102bool Texture2DArray::isDepth(GLint level) const
2103{
Geoff Lange4a492b2014-06-19 14:14:41 -04002104 return GetDepthBits(getInternalFormat(level)) > 0;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002105}
2106
Geoff Lang005df412013-10-16 14:12:50 -04002107void 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 +00002108{
Geoff Lange4a492b2014-06-19 14:14:41 -04002109 GLenum sizedInternalFormat = IsSizedInternalFormat(internalFormat) ? internalFormat
2110 : GetSizedInternalFormat(format, type);
shannonwoods@chromium.org4ad58e02013-05-30 00:08:11 +00002111 redefineImage(level, sizedInternalFormat, width, height, depth);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002112
Geoff Lange4a492b2014-06-19 14:14:41 -04002113 GLsizei inputDepthPitch = gl::GetDepthPitch(sizedInternalFormat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002114
2115 for (int i = 0; i < depth; i++)
2116 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002117 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madill88f18f42013-09-18 14:36:19 -04002118 Texture::setImage(unpack, type, layerPixels, mImageArray[level][i]);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002119 }
2120}
2121
2122void Texture2DArray::setCompressedImage(GLint level, GLenum format, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels)
2123{
2124 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2125 redefineImage(level, format, width, height, depth);
2126
Geoff Lange4a492b2014-06-19 14:14:41 -04002127 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002128
2129 for (int i = 0; i < depth; i++)
2130 {
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002131 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002132 Texture::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2133 }
2134}
2135
Jamie Madill88f18f42013-09-18 14:36:19 -04002136void 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 +00002137{
Geoff Lang005df412013-10-16 14:12:50 -04002138 GLenum internalformat = getInternalFormat(level);
Geoff Lange4a492b2014-06-19 14:14:41 -04002139 GLsizei inputDepthPitch = gl::GetDepthPitch(internalformat, type, width, height, unpack.alignment);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002140
2141 for (int i = 0; i < depth; i++)
2142 {
2143 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002144 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002145
Jamie Madill88f18f42013-09-18 14:36:19 -04002146 if (Texture::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 +00002147 {
2148 commitRect(level, xoffset, yoffset, layer, width, height);
2149 }
2150 }
2151}
2152
2153void Texture2DArray::subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels)
2154{
Geoff Lange4a492b2014-06-19 14:14:41 -04002155 GLsizei inputDepthPitch = gl::GetDepthPitch(format, GL_UNSIGNED_BYTE, width, height, 1);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002156
2157 for (int i = 0; i < depth; i++)
2158 {
2159 int layer = zoffset + i;
Geoff Lang0bbd11c2013-08-21 14:42:01 -04002160 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002161
2162 if (Texture::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]))
2163 {
2164 commitRect(level, xoffset, yoffset, layer, width, height);
2165 }
2166 }
2167}
2168
2169void Texture2DArray::storage(GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2170{
Jamie Madill884a4622013-10-24 17:49:41 -04002171 deleteImages();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002172
2173 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2174 {
Jamie Madill884a4622013-10-24 17:49:41 -04002175 GLsizei levelWidth = std::max(1, width >> level);
2176 GLsizei levelHeight = std::max(1, height >> level);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002177
Jamie Madill884a4622013-10-24 17:49:41 -04002178 mLayerCounts[level] = (level < levels ? depth : 0);
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002179
Jamie Madill884a4622013-10-24 17:49:41 -04002180 if (mLayerCounts[level] > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002181 {
2182 // Create new images for this level
Jamie Madill884a4622013-10-24 17:49:41 -04002183 mImageArray[level] = new rx::Image*[mLayerCounts[level]];
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002184
2185 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002186 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002187 mImageArray[level][layer] = mRenderer->createImage();
2188 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2189 levelHeight, 1, true);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002190 }
2191 }
2192 }
2193
Jamie Madill884a4622013-10-24 17:49:41 -04002194 mImmutable = true;
Nicolas Capensbf712d02014-03-31 14:23:35 -04002195 setCompleteTexStorage(new rx::TextureStorageInterface2DArray(mRenderer, internalformat, IsRenderTargetUsage(mUsage), width, height, depth, levels));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002196}
2197
2198void Texture2DArray::generateMipmaps()
2199{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002200 int baseWidth = getBaseLevelWidth();
2201 int baseHeight = getBaseLevelHeight();
2202 int baseDepth = getBaseLevelDepth();
2203 GLenum baseFormat = getBaseLevelInternalFormat();
2204
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002205 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Geoff Lang98705b72014-03-31 16:00:03 -04002206 int levelCount = mipLevels();
2207 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002208 {
Jamie Madill22f843a2013-10-24 17:49:36 -04002209 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002210 }
2211
2212 if (mTexStorage && mTexStorage->isRenderTarget())
2213 {
Geoff Lang98705b72014-03-31 16:00:03 -04002214 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002215 {
2216 mTexStorage->generateMipmap(level);
2217
2218 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2219 {
2220 mImageArray[level][layer]->markClean();
2221 }
2222 }
2223 }
2224 else
2225 {
Geoff Lang98705b72014-03-31 16:00:03 -04002226 for (int level = 1; level < levelCount; level++)
shannonwoods@chromium.org30aa1a92013-05-30 00:03:13 +00002227 {
2228 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2229 {
2230 mRenderer->generateMipmap(mImageArray[level][layer], mImageArray[level - 1][layer]);
2231 }
2232 }
2233 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002234}
2235
Jamie Madilld3d2a342013-10-07 10:46:35 -04002236const rx::Image *Texture2DArray::getBaseLevelImage() const
2237{
Jamie Madill152ed092013-10-09 17:01:15 -04002238 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
Jamie Madilld3d2a342013-10-07 10:46:35 -04002239}
2240
Jamie Madill2ebab852013-10-24 17:49:42 -04002241rx::TextureStorageInterface *Texture2DArray::getBaseLevelStorage()
2242{
2243 return mTexStorage;
2244}
2245
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002246void Texture2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)
2247{
Jamie Madill07edd442013-07-19 16:36:58 -04002248 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2249 // the current level we're copying to is defined (with appropriate format, width & height)
2250 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2251
2252 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002253 {
2254 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2255 mDirtyImages = true;
2256 }
2257 else
2258 {
Jamie Madille83d1a92013-10-24 17:49:33 -04002259 ensureRenderTarget();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002260
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002261 if (isValidLevel(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002262 {
Jamie Madill169d1112013-10-24 17:49:37 -04002263 updateStorageLevel(level);
Jamie Madill07edd442013-07-19 16:36:58 -04002264
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002265 gl::Rectangle sourceRect;
2266 sourceRect.x = x;
2267 sourceRect.width = width;
2268 sourceRect.y = y;
2269 sourceRect.height = height;
2270
Geoff Lange4a492b2014-06-19 14:14:41 -04002271 mRenderer->copyImage(source, sourceRect, gl::GetFormat(getInternalFormat(0)),
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002272 xoffset, yoffset, zoffset, mTexStorage, level);
2273 }
2274 }
2275}
2276
Jamie Madillf8989902013-07-19 16:36:58 -04002277bool Texture2DArray::isSamplerComplete(const SamplerState &samplerState) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002278{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002279 GLsizei width = getBaseLevelWidth();
2280 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002281 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002282
2283 if (width <= 0 || height <= 0 || depth <= 0)
2284 {
2285 return false;
2286 }
2287
Geoff Langc0b9ef42014-07-02 10:02:37 -04002288 // TODO(geofflang): use context's texture caps
2289 if (!mRenderer->getRendererTextureCaps().get(getBaseLevelInternalFormat()).filtering)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002290 {
Jamie Madillf8989902013-07-19 16:36:58 -04002291 if (samplerState.magFilter != GL_NEAREST ||
2292 (samplerState.minFilter != GL_NEAREST && samplerState.minFilter != GL_NEAREST_MIPMAP_NEAREST))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002293 {
2294 return false;
2295 }
2296 }
2297
Jamie Madillf8989902013-07-19 16:36:58 -04002298 if (IsMipmapFiltered(samplerState) && !isMipmapComplete())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002299 {
2300 return false;
2301 }
2302
2303 return true;
2304}
2305
2306bool Texture2DArray::isMipmapComplete() const
2307{
Geoff Lang98705b72014-03-31 16:00:03 -04002308 int levelCount = mipLevels();
Jamie Madill07edd442013-07-19 16:36:58 -04002309
Geoff Lang98705b72014-03-31 16:00:03 -04002310 for (int level = 1; level < levelCount; level++)
Jamie Madill07edd442013-07-19 16:36:58 -04002311 {
2312 if (!isLevelComplete(level))
2313 {
2314 return false;
2315 }
2316 }
2317
2318 return true;
2319}
2320
2321bool Texture2DArray::isLevelComplete(int level) const
2322{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002323 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
Jamie Madill07edd442013-07-19 16:36:58 -04002324
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002325 if (isImmutable())
2326 {
2327 return true;
2328 }
2329
Jamie Madilld3d2a342013-10-07 10:46:35 -04002330 GLsizei width = getBaseLevelWidth();
2331 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002332 GLsizei layers = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002333
Jamie Madillb8f8b892014-01-07 10:12:50 -05002334 if (width <= 0 || height <= 0 || layers <= 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002335 {
2336 return false;
2337 }
2338
Jamie Madill07edd442013-07-19 16:36:58 -04002339 if (level == 0)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002340 {
Jamie Madill07edd442013-07-19 16:36:58 -04002341 return true;
2342 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002343
Jamie Madill07edd442013-07-19 16:36:58 -04002344 if (getInternalFormat(level) != getInternalFormat(0))
2345 {
2346 return false;
2347 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002348
Jamie Madill07edd442013-07-19 16:36:58 -04002349 if (getWidth(level) != std::max(1, width >> level))
2350 {
2351 return false;
2352 }
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002353
Jamie Madill07edd442013-07-19 16:36:58 -04002354 if (getHeight(level) != std::max(1, height >> level))
2355 {
2356 return false;
2357 }
2358
Jamie Madillb8f8b892014-01-07 10:12:50 -05002359 if (getLayers(level) != layers)
Jamie Madill07edd442013-07-19 16:36:58 -04002360 {
2361 return false;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002362 }
2363
2364 return true;
2365}
2366
Jamie Madille83d1a92013-10-24 17:49:33 -04002367unsigned int Texture2DArray::getRenderTargetSerial(GLint level, GLint layer)
Geoff Lang8040f572013-07-25 16:49:54 -04002368{
Jamie Madille83d1a92013-10-24 17:49:33 -04002369 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(level, layer) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002370}
2371
Jamie Madill07bb8cf2013-10-24 17:49:44 -04002372bool Texture2DArray::isValidLevel(int level) const
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002373{
Nicolas Capensbf712d02014-03-31 14:23:35 -04002374 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002375}
2376
Jamie Madill73b5d062013-10-24 17:49:38 -04002377void Texture2DArray::initializeStorage(bool renderTarget)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002378{
Jamie Madill884a4622013-10-24 17:49:41 -04002379 // Only initialize the first time this texture is used as a render target or shader resource
2380 if (mTexStorage)
2381 {
2382 return;
2383 }
2384
2385 // do not attempt to create storage for nonexistant data
2386 if (!isLevelComplete(0))
2387 {
2388 return;
2389 }
2390
2391 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2392
2393 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2394 ASSERT(mTexStorage);
2395
2396 // flush image data to the storage
2397 updateStorage();
2398}
2399
2400rx::TextureStorageInterface2DArray *Texture2DArray::createCompleteStorage(bool renderTarget) const
2401{
Jamie Madilld3d2a342013-10-07 10:46:35 -04002402 GLsizei width = getBaseLevelWidth();
2403 GLsizei height = getBaseLevelHeight();
Jamie Madillb8f8b892014-01-07 10:12:50 -05002404 GLsizei depth = getLayers(0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002405
Jamie Madill884a4622013-10-24 17:49:41 -04002406 ASSERT(width > 0 && height > 0 && depth > 0);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002407
Jamie Madill884a4622013-10-24 17:49:41 -04002408 // use existing storage level count, when previously specified by TexStorage*D
Nicolas Capensbf712d02014-03-31 14:23:35 -04002409 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002410
Nicolas Capensbf712d02014-03-31 14:23:35 -04002411 return new rx::TextureStorageInterface2DArray(mRenderer, getBaseLevelInternalFormat(), renderTarget, width, height, depth, levels);
Jamie Madill884a4622013-10-24 17:49:41 -04002412}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002413
Jamie Madill884a4622013-10-24 17:49:41 -04002414void Texture2DArray::setCompleteTexStorage(rx::TextureStorageInterface2DArray *newCompleteTexStorage)
2415{
2416 SafeDelete(mTexStorage);
2417 mTexStorage = newCompleteTexStorage;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002418 mDirtyImages = true;
Jamie Madill884a4622013-10-24 17:49:41 -04002419
2420 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2421 ASSERT(!mTexStorage->isManaged());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002422}
2423
Jamie Madill169d1112013-10-24 17:49:37 -04002424void Texture2DArray::updateStorage()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002425{
Geoff Lang946b9482014-05-12 16:37:25 -04002426 ASSERT(mTexStorage != NULL);
2427 GLint storageLevels = mTexStorage->getLevelCount();
2428 for (int level = 0; level < storageLevels; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002429 {
Jamie Madilld9b9a502013-10-10 17:46:13 -04002430 if (isLevelComplete(level))
2431 {
Jamie Madill169d1112013-10-24 17:49:37 -04002432 updateStorageLevel(level);
Jamie Madilld9b9a502013-10-10 17:46:13 -04002433 }
Jamie Madill07edd442013-07-19 16:36:58 -04002434 }
2435}
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002436
Jamie Madill169d1112013-10-24 17:49:37 -04002437void Texture2DArray::updateStorageLevel(int level)
Jamie Madill07edd442013-07-19 16:36:58 -04002438{
Jamie Madillaee7ad82013-10-10 16:07:32 -04002439 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2440 ASSERT(isLevelComplete(level));
2441
Jamie Madill07edd442013-07-19 16:36:58 -04002442 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2443 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002444 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2445 if (mImageArray[level][layer]->isDirty())
Jamie Madill07edd442013-07-19 16:36:58 -04002446 {
Jamie Madillaee7ad82013-10-10 16:07:32 -04002447 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002448 }
2449 }
2450}
2451
Jamie Madille83d1a92013-10-24 17:49:33 -04002452bool Texture2DArray::ensureRenderTarget()
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002453{
Jamie Madill884a4622013-10-24 17:49:41 -04002454 initializeStorage(true);
2455
Jamie Madillb8f8b892014-01-07 10:12:50 -05002456 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
Jamie Madille83d1a92013-10-24 17:49:33 -04002457 {
Jamie Madill884a4622013-10-24 17:49:41 -04002458 ASSERT(mTexStorage);
2459 if (!mTexStorage->isRenderTarget())
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002460 {
Jamie Madill884a4622013-10-24 17:49:41 -04002461 rx::TextureStorageInterface2DArray *newRenderTargetStorage = createCompleteStorage(true);
2462
2463 if (!mRenderer->copyToRenderTarget(newRenderTargetStorage, mTexStorage))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002464 {
Jamie Madill884a4622013-10-24 17:49:41 -04002465 delete newRenderTargetStorage;
Jamie Madille83d1a92013-10-24 17:49:33 -04002466 return gl::error(GL_OUT_OF_MEMORY, false);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002467 }
Jamie Madill884a4622013-10-24 17:49:41 -04002468
2469 setCompleteTexStorage(newRenderTargetStorage);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002470 }
2471 }
2472
Jamie Madille83d1a92013-10-24 17:49:33 -04002473 return (mTexStorage && mTexStorage->isRenderTarget());
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002474}
2475
Geoff Lang8040f572013-07-25 16:49:54 -04002476rx::RenderTarget *Texture2DArray::getRenderTarget(GLint level, GLint layer)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002477{
Geoff Lang8040f572013-07-25 16:49:54 -04002478 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002479 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002480 {
2481 return NULL;
2482 }
2483
Jamie Madill169d1112013-10-24 17:49:37 -04002484 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002485
2486 // ensure this is NOT a depth texture
2487 if (isDepth(level))
2488 {
2489 return NULL;
2490 }
2491
2492 return mTexStorage->getRenderTarget(level, layer);
2493}
2494
2495rx::RenderTarget *Texture2DArray::getDepthStencil(GLint level, GLint layer)
2496{
2497 // ensure the underlying texture is created
Jamie Madill2ebab852013-10-24 17:49:42 -04002498 if (!ensureRenderTarget())
Geoff Lang8040f572013-07-25 16:49:54 -04002499 {
2500 return NULL;
2501 }
2502
Jamie Madill169d1112013-10-24 17:49:37 -04002503 updateStorageLevel(level);
Geoff Lang8040f572013-07-25 16:49:54 -04002504
2505 // ensure this is a depth texture
2506 if (!isDepth(level))
2507 {
2508 return NULL;
2509 }
2510
2511 return mTexStorage->getRenderTarget(level, layer);
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002512}
2513
Geoff Lang005df412013-10-16 14:12:50 -04002514void Texture2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002515{
2516 // If there currently is a corresponding storage texture image, it has these parameters
Jamie Madilld3d2a342013-10-07 10:46:35 -04002517 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2518 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madillb8f8b892014-01-07 10:12:50 -05002519 const int storageDepth = getLayers(0);
Geoff Lang005df412013-10-16 14:12:50 -04002520 const GLenum storageFormat = getBaseLevelInternalFormat();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002521
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002522 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002523 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002524 delete mImageArray[level][layer];
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002525 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002526 delete[] mImageArray[level];
Jamie Madill152ed092013-10-09 17:01:15 -04002527 mImageArray[level] = NULL;
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002528 mLayerCounts[level] = depth;
2529
Jamie Madill152ed092013-10-09 17:01:15 -04002530 if (depth > 0)
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002531 {
Jamie Madill152ed092013-10-09 17:01:15 -04002532 mImageArray[level] = new rx::Image*[depth]();
2533
2534 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2535 {
2536 mImageArray[level][layer] = mRenderer->createImage();
2537 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2538 }
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002539 }
2540
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002541 if (mTexStorage)
2542 {
Nicolas Capensbf712d02014-03-31 14:23:35 -04002543 const int storageLevels = mTexStorage->getLevelCount();
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002544
2545 if ((level >= storageLevels && storageLevels != 0) ||
2546 width != storageWidth ||
2547 height != storageHeight ||
2548 depth != storageDepth ||
2549 internalformat != storageFormat) // Discard mismatched storage
2550 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002551 for (int level = 0; level < IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002552 {
shannonwoods@chromium.org644f7662013-05-30 00:02:07 +00002553 for (int layer = 0; layer < mLayerCounts[level]; layer++)
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002554 {
2555 mImageArray[level][layer]->markDirty();
2556 }
2557 }
2558
2559 delete mTexStorage;
2560 mTexStorage = NULL;
2561 mDirtyImages = true;
2562 }
2563 }
2564}
2565
2566void Texture2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
2567{
Jamie Madillb8f8b892014-01-07 10:12:50 -05002568 if (isValidLevel(level) && layerTarget < getLayers(level))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002569 {
Brandon Jones6518fe22014-07-08 15:16:52 -07002570 rx::ImageD3D *image = rx::ImageD3D::makeImageD3D(mImageArray[level][layerTarget]);
Jamie Madill169d1112013-10-24 17:49:37 -04002571 if (image->copyToStorage(mTexStorage, level, xoffset, yoffset, layerTarget, width, height))
shannon.woods%transgaming.com@gtempaccount.com7625f792013-04-13 03:46:07 +00002572 {
2573 image->markClean();
2574 }
2575 }
2576}
2577
daniel@transgaming.com95a758f2012-07-12 15:17:06 +00002578}