blob: 5554e8060f4599755a0e510e592b7481ba18f6b6 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/Buffer.h"
13#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Brandon Jonesf47bebc2014-07-09 14:28:42 -070029bool IsRenderTargetUsage(GLenum usage)
30{
31 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
32}
33
Brandon Jones78b1acd2014-07-15 15:33:07 -070034TextureD3D::TextureD3D(Renderer *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070035 : mRenderer(renderer),
36 mUsage(GL_NONE),
37 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040038 mImmutable(false),
39 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070040{
41}
42
43TextureD3D::~TextureD3D()
44{
45}
46
Brandon Jones6053a522014-07-25 16:22:09 -070047TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
48{
49 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
50 return static_cast<TextureD3D*>(texture);
51}
52
Jamie Madill2f06dbf2014-09-18 15:08:50 -040053TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070054{
55 // ensure the underlying texture is created
56 initializeStorage(false);
57
Jamie Madill98553e32014-09-30 16:33:50 -040058 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070059 {
60 updateStorage();
61 }
62
Jamie Madill98553e32014-09-30 16:33:50 -040063 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070064}
65
Brandon Jonesf47bebc2014-07-09 14:28:42 -070066GLint TextureD3D::getBaseLevelWidth() const
67{
Brandon Jones78b1acd2014-07-15 15:33:07 -070068 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 return (baseImage ? baseImage->getWidth() : 0);
70}
71
72GLint TextureD3D::getBaseLevelHeight() const
73{
Brandon Jones78b1acd2014-07-15 15:33:07 -070074 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075 return (baseImage ? baseImage->getHeight() : 0);
76}
77
78GLint TextureD3D::getBaseLevelDepth() const
79{
Brandon Jones78b1acd2014-07-15 15:33:07 -070080 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070081 return (baseImage ? baseImage->getDepth() : 0);
82}
83
84// Note: "base level image" is loosely defined to be any image from the base level,
85// where in the base of 2D array textures and cube maps there are several. Don't use
86// the base level image for anything except querying texture format and size.
87GLenum TextureD3D::getBaseLevelInternalFormat() const
88{
Brandon Jones78b1acd2014-07-15 15:33:07 -070089 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -070090 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
91}
92
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040093gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070094{
95 // No-op
96 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
97 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -040098 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -070099 }
100
101 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
102 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
103 const void *pixelData = pixels;
104
105 if (unpack.pixelBuffer.id() != 0)
106 {
107 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
108 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
109 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
110 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
111 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
112 const void *bufferData = pixelBuffer->getImplementation()->getData();
113 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
114 }
115
116 if (pixelData != NULL)
117 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400118 gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
119 if (error.isError())
120 {
121 return error;
122 }
123
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 mDirtyImages = true;
125 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400126
127 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700128}
129
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400130gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
131 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700132{
133 const void *pixelData = pixels;
134
135 // CPU readback & copy where direct GPU copy is not supported
136 if (unpack.pixelBuffer.id() != 0)
137 {
138 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
139 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
140 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
141 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
142 const void *bufferData = pixelBuffer->getImplementation()->getData();
143 pixelData = static_cast<const unsigned char *>(bufferData) + offset;
144 }
145
146 if (pixelData != NULL)
147 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400148 Image *image = getImage(index);
149 ASSERT(image);
150
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400151 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
152 type, pixelData);
153 if (error.isError())
154 {
155 return error;
156 }
157
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700158 mDirtyImages = true;
159 }
160
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400161 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700162}
163
Geoff Langb5348332014-09-02 13:16:34 -0400164gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165{
166 if (pixels != NULL)
167 {
Geoff Langb5348332014-09-02 13:16:34 -0400168 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
169 if (error.isError())
170 {
171 return error;
172 }
173
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174 mDirtyImages = true;
175 }
Geoff Langb5348332014-09-02 13:16:34 -0400176
177 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700178}
179
Geoff Langb5348332014-09-02 13:16:34 -0400180gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700181 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700182{
183 if (pixels != NULL)
184 {
Geoff Langb5348332014-09-02 13:16:34 -0400185 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
186 if (error.isError())
187 {
188 return error;
189 }
190
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191 mDirtyImages = true;
192 }
193
Geoff Langb5348332014-09-02 13:16:34 -0400194 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195}
196
197bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
198{
199 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
200}
201
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400202gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
203 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700204{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400205 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700206 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
207 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400208 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700209 }
210
211 // In order to perform the fast copy through the shader, we must have the right format, and be able
212 // to create a render target.
213 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
214
215 unsigned int offset = reinterpret_cast<unsigned int>(pixels);
216
Geoff Langae5122c2014-08-27 14:08:43 -0400217 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
218 if (error.isError())
219 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400220 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400221 }
222
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400223 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700224}
225
226GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
227{
228 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
229 {
230 // Maximum number of levels
231 return gl::log2(std::max(std::max(width, height), depth)) + 1;
232 }
233 else
234 {
235 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
236 return 1;
237 }
238}
239
240int TextureD3D::mipLevels() const
241{
242 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
243}
244
Jamie Madill98553e32014-09-30 16:33:50 -0400245TextureStorage *TextureD3D::getStorage()
246{
247 return mTexStorage;
248}
249
Jamie Madill4aa79e12014-09-29 10:46:14 -0400250void TextureD3D::generateMipmaps()
251{
252 // Set up proper image sizes.
253 initMipmapsImages();
254
255 // We know that all layers have the same dimension, for the texture to be complete
256 GLint layerCount = static_cast<GLint>(getLayerCount(0));
257 GLint mipCount = mipLevels();
258
259 // The following will create and initialize the storage, or update it if it exists
260 TextureStorage *storage = getNativeTexture();
261
262 bool renderableStorage = (storage && storage->isRenderTarget());
263
264 for (GLint layer = 0; layer < layerCount; ++layer)
265 {
266 for (GLint mip = 1; mip < mipCount; ++mip)
267 {
268 ASSERT(getLayerCount(mip) == layerCount);
269
270 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
271 gl::ImageIndex destIndex = getImageIndex(mip, layer);
272
273 if (renderableStorage)
274 {
275 // GPU-side mipmapping
276 storage->generateMipmap(sourceIndex, destIndex);
277 }
278 else
279 {
280 // CPU-side mipmapping
281 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
282 }
283 }
284 }
285}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700286
Brandon Jones78b1acd2014-07-15 15:33:07 -0700287TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400288 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700289{
290 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
291 {
292 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
293 }
294}
295
296TextureD3D_2D::~TextureD3D_2D()
297{
Austin Kinross69822602014-08-12 15:51:37 -0700298 // Delete the Images before the TextureStorage.
299 // Images might be relying on the TextureStorage for some of their data.
300 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700301 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
302 {
303 delete mImageArray[i];
304 }
Austin Kinross69822602014-08-12 15:51:37 -0700305
306 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700307}
308
Brandon Jonescef06ff2014-08-05 13:27:48 -0700309Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700310{
311 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700312 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700313 return mImageArray[level];
314}
315
Jamie Madillfeda4d22014-09-17 13:03:29 -0400316Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
317{
318 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400319 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400320 ASSERT(index.type == GL_TEXTURE_2D);
321 return mImageArray[index.mipIndex];
322}
323
Brandon Jonescef06ff2014-08-05 13:27:48 -0700324GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700325{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700326 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
327 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700328}
329
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700330GLsizei TextureD3D_2D::getWidth(GLint level) const
331{
332 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
333 return mImageArray[level]->getWidth();
334 else
335 return 0;
336}
337
338GLsizei TextureD3D_2D::getHeight(GLint level) const
339{
340 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
341 return mImageArray[level]->getHeight();
342 else
343 return 0;
344}
345
346GLenum TextureD3D_2D::getInternalFormat(GLint level) const
347{
348 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
349 return mImageArray[level]->getInternalFormat();
350 else
351 return GL_NONE;
352}
353
354GLenum TextureD3D_2D::getActualFormat(GLint level) const
355{
356 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
357 return mImageArray[level]->getActualFormat();
358 else
359 return GL_NONE;
360}
361
362bool TextureD3D_2D::isDepth(GLint level) const
363{
Geoff Lang5d601382014-07-22 15:14:06 -0400364 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700365}
366
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400367gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
368 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
369 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700371 ASSERT(target == GL_TEXTURE_2D && depth == 1);
372
Geoff Lang5d601382014-07-22 15:14:06 -0400373 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
374
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700375 bool fastUnpacked = false;
376
Brandon Jonescef06ff2014-08-05 13:27:48 -0700377 redefineImage(level, sizedInternalFormat, width, height);
378
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700379 // Attempt a fast gpu copy of the pixel data to the surface
380 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
381 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400382 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
383
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700384 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400385 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700386 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
387
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400388 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700389 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400390 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
391 if (error.isError())
392 {
393 return error;
394 }
395
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700396 // Ensure we don't overwrite our newly initialized data
397 mImageArray[level]->markClean();
398
399 fastUnpacked = true;
400 }
401 }
402
403 if (!fastUnpacked)
404 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400405 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
406 if (error.isError())
407 {
408 return error;
409 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700410 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400411
412 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700413}
414
Geoff Langb5348332014-09-02 13:16:34 -0400415gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
416 GLsizei width, GLsizei height, GLsizei depth,
417 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700418{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700419 ASSERT(target == GL_TEXTURE_2D && depth == 1);
420
421 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
422 redefineImage(level, format, width, height);
423
Geoff Langb5348332014-09-02 13:16:34 -0400424 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700425}
426
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400427gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
428 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
429 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700430{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700431 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
432
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700433 bool fastUnpacked = false;
434
Jamie Madillac7579c2014-09-17 16:59:33 -0400435 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700436 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
437 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400438 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700439 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
440
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400441 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400443 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
444 if (error.isError())
445 {
446 return error;
447 }
448
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700449 // Ensure we don't overwrite our newly initialized data
450 mImageArray[level]->markClean();
451
452 fastUnpacked = true;
453 }
454 }
455
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400456 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700457 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400458 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
459 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
460 pixels, index);
461 if (error.isError())
462 {
463 return error;
464 }
465
466 error = commitRect(level, xoffset, yoffset, width, height);
467 if (error.isError())
468 {
469 return error;
470 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700471 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400472
473 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700474}
475
Geoff Langb5348332014-09-02 13:16:34 -0400476gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
477 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
478 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700479{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700480 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
481
Geoff Langb5348332014-09-02 13:16:34 -0400482 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
483 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700484 {
Geoff Langb5348332014-09-02 13:16:34 -0400485 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700486 }
Geoff Langb5348332014-09-02 13:16:34 -0400487
488 error = commitRect(level, xoffset, yoffset, width, height);
489 if (error.isError())
490 {
491 return error;
492 }
493
494 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700495}
496
Brandon Jonescef06ff2014-08-05 13:27:48 -0700497void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700498{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700499 ASSERT(target == GL_TEXTURE_2D);
500
501 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
502 redefineImage(level, sizedInternalFormat, width, height);
503
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700504 if (!mImageArray[level]->isRenderableFormat())
505 {
506 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
507 mDirtyImages = true;
508 }
509 else
510 {
511 ensureRenderTarget();
512 mImageArray[level]->markClean();
513
514 if (width != 0 && height != 0 && isValidLevel(level))
515 {
516 gl::Rectangle sourceRect;
517 sourceRect.x = x;
518 sourceRect.width = width;
519 sourceRect.y = y;
520 sourceRect.height = height;
521
Jamie Madill856d9d42014-09-18 15:08:49 -0400522 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700523 }
524 }
525}
526
527void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
528{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700529 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
530
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
532 // the current level we're copying to is defined (with appropriate format, width & height)
533 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
534
535 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
536 {
537 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
538 mDirtyImages = true;
539 }
540 else
541 {
542 ensureRenderTarget();
543
544 if (isValidLevel(level))
545 {
546 updateStorageLevel(level);
547
548 gl::Rectangle sourceRect;
549 sourceRect.x = x;
550 sourceRect.width = width;
551 sourceRect.y = y;
552 sourceRect.height = height;
553
Jamie Madill856d9d42014-09-18 15:08:49 -0400554 mRenderer->copyImage2D(source, sourceRect,
555 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
556 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700557 }
558 }
559}
560
Brandon Jonescef06ff2014-08-05 13:27:48 -0700561void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700562{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700563 ASSERT(target == GL_TEXTURE_2D && depth == 1);
564
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700565 for (int level = 0; level < levels; level++)
566 {
567 GLsizei levelWidth = std::max(1, width >> level);
568 GLsizei levelHeight = std::max(1, height >> level);
569 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
570 }
571
572 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
573 {
574 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
575 }
576
577 mImmutable = true;
578
Jamie Madillc4833262014-09-18 16:18:26 -0400579 bool renderTarget = IsRenderTargetUsage(mUsage);
580 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400581 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582}
583
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700584void TextureD3D_2D::bindTexImage(egl::Surface *surface)
585{
586 GLenum internalformat = surface->getFormat();
587
588 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
589
590 if (mTexStorage)
591 {
592 SafeDelete(mTexStorage);
593 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400594
595 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596
597 mDirtyImages = true;
598}
599
600void TextureD3D_2D::releaseTexImage()
601{
602 if (mTexStorage)
603 {
604 SafeDelete(mTexStorage);
605 }
606
607 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
608 {
609 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
610 }
611}
612
Jamie Madill4aa79e12014-09-29 10:46:14 -0400613void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700615 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700617 for (int level = 1; level < levelCount; level++)
618 {
619 redefineImage(level, getBaseLevelInternalFormat(),
620 std::max(getBaseLevelWidth() >> level, 1),
621 std::max(getBaseLevelHeight() >> level, 1));
622 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700623}
624
Jamie Madillac7579c2014-09-17 16:59:33 -0400625unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700626{
Jamie Madillac7579c2014-09-17 16:59:33 -0400627 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400628 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700629}
630
Jamie Madillac7579c2014-09-17 16:59:33 -0400631RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632{
Jamie Madillac7579c2014-09-17 16:59:33 -0400633 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700634
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635 // ensure the underlying texture is created
636 if (!ensureRenderTarget())
637 {
638 return NULL;
639 }
640
Jamie Madillac7579c2014-09-17 16:59:33 -0400641 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400642 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643}
644
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700645bool TextureD3D_2D::isValidLevel(int level) const
646{
647 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
648}
649
650bool TextureD3D_2D::isLevelComplete(int level) const
651{
652 if (isImmutable())
653 {
654 return true;
655 }
656
Brandon Jones78b1acd2014-07-15 15:33:07 -0700657 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700658
659 GLsizei width = baseImage->getWidth();
660 GLsizei height = baseImage->getHeight();
661
662 if (width <= 0 || height <= 0)
663 {
664 return false;
665 }
666
667 // The base image level is complete if the width and height are positive
668 if (level == 0)
669 {
670 return true;
671 }
672
673 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700674 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700675
676 if (image->getInternalFormat() != baseImage->getInternalFormat())
677 {
678 return false;
679 }
680
681 if (image->getWidth() != std::max(1, width >> level))
682 {
683 return false;
684 }
685
686 if (image->getHeight() != std::max(1, height >> level))
687 {
688 return false;
689 }
690
691 return true;
692}
693
694// Constructs a native texture resource from the texture images
695void TextureD3D_2D::initializeStorage(bool renderTarget)
696{
697 // Only initialize the first time this texture is used as a render target or shader resource
698 if (mTexStorage)
699 {
700 return;
701 }
702
703 // do not attempt to create storage for nonexistant data
704 if (!isLevelComplete(0))
705 {
706 return;
707 }
708
709 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
710
711 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
712 ASSERT(mTexStorage);
713
714 // flush image data to the storage
715 updateStorage();
716}
717
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400718TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700719{
720 GLsizei width = getBaseLevelWidth();
721 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400722 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700723
724 ASSERT(width > 0 && height > 0);
725
726 // use existing storage level count, when previously specified by TexStorage*D
727 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
728
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400729 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700730}
731
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400732void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733{
734 SafeDelete(mTexStorage);
735 mTexStorage = newCompleteTexStorage;
736
737 if (mTexStorage && mTexStorage->isManaged())
738 {
739 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
740 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400741 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742 }
743 }
744
745 mDirtyImages = true;
746}
747
748void TextureD3D_2D::updateStorage()
749{
750 ASSERT(mTexStorage != NULL);
751 GLint storageLevels = mTexStorage->getLevelCount();
752 for (int level = 0; level < storageLevels; level++)
753 {
754 if (mImageArray[level]->isDirty() && isLevelComplete(level))
755 {
756 updateStorageLevel(level);
757 }
758 }
759}
760
761bool TextureD3D_2D::ensureRenderTarget()
762{
763 initializeStorage(true);
764
765 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0)
766 {
767 ASSERT(mTexStorage);
768 if (!mTexStorage->isRenderTarget())
769 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400770 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700771
Jamie Madill98553e32014-09-30 16:33:50 -0400772 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700773 {
774 delete newRenderTargetStorage;
775 return gl::error(GL_OUT_OF_MEMORY, false);
776 }
777
778 setCompleteTexStorage(newRenderTargetStorage);
779 }
780 }
781
782 return (mTexStorage && mTexStorage->isRenderTarget());
783}
784
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785const ImageD3D *TextureD3D_2D::getBaseLevelImage() const
786{
787 return mImageArray[0];
788}
789
790void TextureD3D_2D::updateStorageLevel(int level)
791{
792 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
793 ASSERT(isLevelComplete(level));
794
795 if (mImageArray[level]->isDirty())
796 {
797 commitRect(level, 0, 0, getWidth(level), getHeight(level));
798 }
799}
800
801void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
802{
803 // If there currently is a corresponding storage texture image, it has these parameters
804 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
805 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
806 const GLenum storageFormat = getBaseLevelInternalFormat();
807
808 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
809
810 if (mTexStorage)
811 {
812 const int storageLevels = mTexStorage->getLevelCount();
813
814 if ((level >= storageLevels && storageLevels != 0) ||
815 width != storageWidth ||
816 height != storageHeight ||
817 internalformat != storageFormat) // Discard mismatched storage
818 {
819 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
820 {
821 mImageArray[i]->markDirty();
822 }
823
824 SafeDelete(mTexStorage);
825 mDirtyImages = true;
826 }
827 }
828}
829
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400830gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700831{
832 if (isValidLevel(level))
833 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700834 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400835 gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
836 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700837 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400838 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700839 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400840
841 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700842 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400843
844 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700845}
846
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400847gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
848{
849 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
850}
Brandon Jones0511e802014-07-14 16:27:26 -0700851
Jamie Madillcb83dc12014-09-29 10:46:12 -0400852gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
853{
854 // "layer" does not apply to 2D Textures.
855 return gl::ImageIndex::Make2D(mip);
856}
857
Brandon Jones78b1acd2014-07-15 15:33:07 -0700858TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400859 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700860{
861 for (int i = 0; i < 6; i++)
862 {
863 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
864 {
865 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
866 }
867 }
868}
869
870TextureD3D_Cube::~TextureD3D_Cube()
871{
Austin Kinross69822602014-08-12 15:51:37 -0700872 // Delete the Images before the TextureStorage.
873 // Images might be relying on the TextureStorage for some of their data.
874 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -0700875 for (int i = 0; i < 6; i++)
876 {
877 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
878 {
879 SafeDelete(mImageArray[i][j]);
880 }
881 }
Austin Kinross69822602014-08-12 15:51:37 -0700882
883 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700884}
885
Brandon Jonescef06ff2014-08-05 13:27:48 -0700886Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700887{
888 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700889 ASSERT(layer < 6);
890 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700891}
892
Jamie Madillfeda4d22014-09-17 13:03:29 -0400893Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
894{
895 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
896 ASSERT(index.layerIndex < 6);
897 return mImageArray[index.layerIndex][index.mipIndex];
898}
899
Brandon Jonescef06ff2014-08-05 13:27:48 -0700900GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700901{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700902 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
903 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700904}
905
Brandon Jonescef06ff2014-08-05 13:27:48 -0700906GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700907{
908 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700909 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700910 else
911 return GL_NONE;
912}
913
Brandon Jonescef06ff2014-08-05 13:27:48 -0700914bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700915{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700916 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700917}
918
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400919gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
920 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
921 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700922{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700923 ASSERT(depth == 1);
924
925 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400926 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700927
928 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
929
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400930 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700931}
932
Geoff Langb5348332014-09-02 13:16:34 -0400933gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
934 GLsizei width, GLsizei height, GLsizei depth,
935 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700936{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700937 ASSERT(depth == 1);
938
Brandon Jones0511e802014-07-14 16:27:26 -0700939 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700940 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
941
Brandon Jones0511e802014-07-14 16:27:26 -0700942 redefineImage(faceIndex, level, format, width, height);
943
Geoff Langb5348332014-09-02 13:16:34 -0400944 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700945}
946
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400947gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
948 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
949 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700950{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700951 ASSERT(depth == 1 && zoffset == 0);
952
953 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
954
Jamie Madillfeda4d22014-09-17 13:03:29 -0400955 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400956 gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
957 index);
958 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700959 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400960 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700961 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400962
963 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
964 if (error.isError())
965 {
966 return error;
967 }
968
969 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700970}
971
Geoff Langb5348332014-09-02 13:16:34 -0400972gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
973 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
974 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700975{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700976 ASSERT(depth == 1 && zoffset == 0);
977
978 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
979
Geoff Langb5348332014-09-02 13:16:34 -0400980 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]);
981 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700982 {
Geoff Langb5348332014-09-02 13:16:34 -0400983 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700984 }
Geoff Langb5348332014-09-02 13:16:34 -0400985
986 error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
987 if (error.isError())
988 {
989 return error;
990 }
991
992 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -0700993}
994
995void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
996{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700997 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400998 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
999
Brandon Jones0511e802014-07-14 16:27:26 -07001000 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1001
1002 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1003 {
1004 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1005 mDirtyImages = true;
1006 }
1007 else
1008 {
1009 ensureRenderTarget();
1010 mImageArray[faceIndex][level]->markClean();
1011
1012 ASSERT(width == height);
1013
1014 if (width > 0 && isValidFaceLevel(faceIndex, level))
1015 {
1016 gl::Rectangle sourceRect;
1017 sourceRect.x = x;
1018 sourceRect.width = width;
1019 sourceRect.y = y;
1020 sourceRect.height = height;
1021
Jamie Madill856d9d42014-09-18 15:08:49 -04001022 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001023 }
1024 }
1025}
1026
1027void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1028{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001029 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001030
1031 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1032 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1033 // rely on the "getBaseLevel*" methods reliably otherwise.
1034 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1035
1036 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1037 {
1038 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1039 mDirtyImages = true;
1040 }
1041 else
1042 {
1043 ensureRenderTarget();
1044
1045 if (isValidFaceLevel(faceIndex, level))
1046 {
1047 updateStorageFaceLevel(faceIndex, level);
1048
1049 gl::Rectangle sourceRect;
1050 sourceRect.x = x;
1051 sourceRect.width = width;
1052 sourceRect.y = y;
1053 sourceRect.height = height;
1054
Jamie Madill856d9d42014-09-18 15:08:49 -04001055 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1056 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001057 }
1058 }
1059}
1060
Brandon Jonescef06ff2014-08-05 13:27:48 -07001061void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001062{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001063 ASSERT(width == height);
1064 ASSERT(depth == 1);
1065
Brandon Jones0511e802014-07-14 16:27:26 -07001066 for (int level = 0; level < levels; level++)
1067 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001068 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001069 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1070 {
1071 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1072 }
1073 }
1074
1075 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1076 {
1077 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1078 {
1079 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1080 }
1081 }
1082
1083 mImmutable = true;
1084
Jamie Madillc4833262014-09-18 16:18:26 -04001085 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001086 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1087 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001088}
1089
Brandon Jones0511e802014-07-14 16:27:26 -07001090// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1091bool TextureD3D_Cube::isCubeComplete() const
1092{
1093 int baseWidth = getBaseLevelWidth();
1094 int baseHeight = getBaseLevelHeight();
1095 GLenum baseFormat = getBaseLevelInternalFormat();
1096
1097 if (baseWidth <= 0 || baseWidth != baseHeight)
1098 {
1099 return false;
1100 }
1101
1102 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1103 {
1104 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1105
1106 if (faceBaseImage.getWidth() != baseWidth ||
1107 faceBaseImage.getHeight() != baseHeight ||
1108 faceBaseImage.getInternalFormat() != baseFormat )
1109 {
1110 return false;
1111 }
1112 }
1113
1114 return true;
1115}
1116
Brandon Jones6053a522014-07-25 16:22:09 -07001117void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1118{
1119 UNREACHABLE();
1120}
1121
1122void TextureD3D_Cube::releaseTexImage()
1123{
1124 UNREACHABLE();
1125}
1126
1127
Jamie Madill4aa79e12014-09-29 10:46:14 -04001128void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001129{
1130 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1131 int levelCount = mipLevels();
1132 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1133 {
1134 for (int level = 1; level < levelCount; level++)
1135 {
1136 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1137 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1138 }
1139 }
Brandon Jones0511e802014-07-14 16:27:26 -07001140}
1141
Jamie Madillac7579c2014-09-17 16:59:33 -04001142unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001143{
Jamie Madillc4833262014-09-18 16:18:26 -04001144 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001145}
1146
Jamie Madillac7579c2014-09-17 16:59:33 -04001147RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001148{
Jamie Madillac7579c2014-09-17 16:59:33 -04001149 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001150
1151 // ensure the underlying texture is created
1152 if (!ensureRenderTarget())
1153 {
1154 return NULL;
1155 }
1156
Jamie Madillac7579c2014-09-17 16:59:33 -04001157 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001158 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001159}
1160
Brandon Jones0511e802014-07-14 16:27:26 -07001161void TextureD3D_Cube::initializeStorage(bool renderTarget)
1162{
1163 // Only initialize the first time this texture is used as a render target or shader resource
1164 if (mTexStorage)
1165 {
1166 return;
1167 }
1168
1169 // do not attempt to create storage for nonexistant data
1170 if (!isFaceLevelComplete(0, 0))
1171 {
1172 return;
1173 }
1174
1175 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1176
1177 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1178 ASSERT(mTexStorage);
1179
1180 // flush image data to the storage
1181 updateStorage();
1182}
1183
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001184TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001185{
1186 GLsizei size = getBaseLevelWidth();
1187
1188 ASSERT(size > 0);
1189
1190 // use existing storage level count, when previously specified by TexStorage*D
1191 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1192
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001193 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001194}
1195
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001196void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001197{
1198 SafeDelete(mTexStorage);
1199 mTexStorage = newCompleteTexStorage;
1200
1201 if (mTexStorage && mTexStorage->isManaged())
1202 {
1203 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1204 {
1205 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1206 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001207 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001208 }
1209 }
1210 }
1211
1212 mDirtyImages = true;
1213}
1214
1215void TextureD3D_Cube::updateStorage()
1216{
1217 ASSERT(mTexStorage != NULL);
1218 GLint storageLevels = mTexStorage->getLevelCount();
1219 for (int face = 0; face < 6; face++)
1220 {
1221 for (int level = 0; level < storageLevels; level++)
1222 {
1223 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1224 {
1225 updateStorageFaceLevel(face, level);
1226 }
1227 }
1228 }
1229}
1230
1231bool TextureD3D_Cube::ensureRenderTarget()
1232{
1233 initializeStorage(true);
1234
1235 if (getBaseLevelWidth() > 0)
1236 {
1237 ASSERT(mTexStorage);
1238 if (!mTexStorage->isRenderTarget())
1239 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001240 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones0511e802014-07-14 16:27:26 -07001241
Jamie Madill98553e32014-09-30 16:33:50 -04001242 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001243 {
1244 delete newRenderTargetStorage;
1245 return gl::error(GL_OUT_OF_MEMORY, false);
1246 }
1247
1248 setCompleteTexStorage(newRenderTargetStorage);
1249 }
1250 }
1251
1252 return (mTexStorage && mTexStorage->isRenderTarget());
1253}
1254
Brandon Jones0511e802014-07-14 16:27:26 -07001255const ImageD3D *TextureD3D_Cube::getBaseLevelImage() const
1256{
1257 // Note: if we are not cube-complete, there is no single base level image that can describe all
1258 // cube faces, so this method is only well-defined for a cube-complete base level.
1259 return mImageArray[0][0];
1260}
1261
Brandon Jones0511e802014-07-14 16:27:26 -07001262bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1263{
1264 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1265}
1266
Brandon Jones0511e802014-07-14 16:27:26 -07001267bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1268{
1269 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1270
1271 if (isImmutable())
1272 {
1273 return true;
1274 }
1275
1276 int baseSize = getBaseLevelWidth();
1277
1278 if (baseSize <= 0)
1279 {
1280 return false;
1281 }
1282
1283 // "isCubeComplete" checks for base level completeness and we must call that
1284 // to determine if any face at level 0 is complete. We omit that check here
1285 // to avoid re-checking cube-completeness for every face at level 0.
1286 if (level == 0)
1287 {
1288 return true;
1289 }
1290
1291 // Check that non-zero levels are consistent with the base level.
1292 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1293
1294 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1295 {
1296 return false;
1297 }
1298
1299 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1300 {
1301 return false;
1302 }
1303
1304 return true;
1305}
1306
1307void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1308{
1309 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1310 ImageD3D *image = mImageArray[faceIndex][level];
1311
1312 if (image->isDirty())
1313 {
1314 commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
1315 }
1316}
1317
1318void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1319{
1320 // If there currently is a corresponding storage texture image, it has these parameters
1321 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1322 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1323 const GLenum storageFormat = getBaseLevelInternalFormat();
1324
1325 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1326
1327 if (mTexStorage)
1328 {
1329 const int storageLevels = mTexStorage->getLevelCount();
1330
1331 if ((level >= storageLevels && storageLevels != 0) ||
1332 width != storageWidth ||
1333 height != storageHeight ||
1334 internalformat != storageFormat) // Discard mismatched storage
1335 {
1336 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1337 {
1338 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1339 {
1340 mImageArray[faceIndex][level]->markDirty();
1341 }
1342 }
1343
1344 SafeDelete(mTexStorage);
1345
1346 mDirtyImages = true;
1347 }
1348 }
1349}
1350
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001351gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
Brandon Jones0511e802014-07-14 16:27:26 -07001352{
1353 if (isValidFaceLevel(faceIndex, level))
1354 {
1355 ImageD3D *image = mImageArray[faceIndex][level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001356 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
1357 if (error.isError())
1358 {
1359 return error;
1360 }
1361
1362 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001363 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001364
1365 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001366}
1367
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001368gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1369{
1370 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1371}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001372
Jamie Madillcb83dc12014-09-29 10:46:12 -04001373gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1374{
1375 // The "layer" of the image index corresponds to the cube face
1376 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1377}
1378
Brandon Jones78b1acd2014-07-15 15:33:07 -07001379TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001380 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001381{
1382 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1383 {
1384 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1385 }
1386}
1387
1388TextureD3D_3D::~TextureD3D_3D()
1389{
Austin Kinross69822602014-08-12 15:51:37 -07001390 // Delete the Images before the TextureStorage.
1391 // Images might be relying on the TextureStorage for some of their data.
1392 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones78b1acd2014-07-15 15:33:07 -07001393 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1394 {
1395 delete mImageArray[i];
1396 }
Austin Kinross69822602014-08-12 15:51:37 -07001397
1398 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001399}
1400
Brandon Jonescef06ff2014-08-05 13:27:48 -07001401Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001402{
1403 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001404 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001405 return mImageArray[level];
1406}
1407
Jamie Madillfeda4d22014-09-17 13:03:29 -04001408Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1409{
1410 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001411 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001412 ASSERT(index.type == GL_TEXTURE_3D);
1413 return mImageArray[index.mipIndex];
1414}
1415
Brandon Jonescef06ff2014-08-05 13:27:48 -07001416GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001417{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001418 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1419 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001420}
1421
Brandon Jones78b1acd2014-07-15 15:33:07 -07001422GLsizei TextureD3D_3D::getWidth(GLint level) const
1423{
1424 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1425 return mImageArray[level]->getWidth();
1426 else
1427 return 0;
1428}
1429
1430GLsizei TextureD3D_3D::getHeight(GLint level) const
1431{
1432 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1433 return mImageArray[level]->getHeight();
1434 else
1435 return 0;
1436}
1437
1438GLsizei TextureD3D_3D::getDepth(GLint level) const
1439{
1440 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1441 return mImageArray[level]->getDepth();
1442 else
1443 return 0;
1444}
1445
1446GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1447{
1448 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1449 return mImageArray[level]->getInternalFormat();
1450 else
1451 return GL_NONE;
1452}
1453
1454bool TextureD3D_3D::isDepth(GLint level) const
1455{
Geoff Lang5d601382014-07-22 15:14:06 -04001456 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001457}
1458
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001459gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1460 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1461 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001462{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001463 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001464 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1465
Brandon Jones78b1acd2014-07-15 15:33:07 -07001466 redefineImage(level, sizedInternalFormat, width, height, depth);
1467
1468 bool fastUnpacked = false;
1469
1470 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1471 if (isFastUnpackable(unpack, sizedInternalFormat))
1472 {
1473 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001474 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1475 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001476 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1477
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001478 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001479 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001480 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1481 if (error.isError())
1482 {
1483 return error;
1484 }
1485
Brandon Jones78b1acd2014-07-15 15:33:07 -07001486 // Ensure we don't overwrite our newly initialized data
1487 mImageArray[level]->markClean();
1488
1489 fastUnpacked = true;
1490 }
1491 }
1492
1493 if (!fastUnpacked)
1494 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001495 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1496 if (error.isError())
1497 {
1498 return error;
1499 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001501
1502 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503}
1504
Geoff Langb5348332014-09-02 13:16:34 -04001505gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1506 GLsizei width, GLsizei height,GLsizei depth,
1507 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001508{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001509 ASSERT(target == GL_TEXTURE_3D);
1510
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1512 redefineImage(level, format, width, height, depth);
1513
Geoff Langb5348332014-09-02 13:16:34 -04001514 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001515}
1516
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001517gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1518 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1519 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001520{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001521 ASSERT(target == GL_TEXTURE_3D);
1522
Brandon Jones78b1acd2014-07-15 15:33:07 -07001523 bool fastUnpacked = false;
1524
Jamie Madillac7579c2014-09-17 16:59:33 -04001525 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1526
Brandon Jones78b1acd2014-07-15 15:33:07 -07001527 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1528 if (isFastUnpackable(unpack, getInternalFormat(level)))
1529 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001530 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001531 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1532
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001533 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001534 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001535 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1536 if (error.isError())
1537 {
1538 return error;
1539 }
1540
Brandon Jones78b1acd2014-07-15 15:33:07 -07001541 // Ensure we don't overwrite our newly initialized data
1542 mImageArray[level]->markClean();
1543
1544 fastUnpacked = true;
1545 }
1546 }
1547
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001548 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001549 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001550 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1551 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
1552 pixels, index);
1553 if (error.isError())
1554 {
1555 return error;
1556 }
1557
1558 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1559 if (error.isError())
1560 {
1561 return error;
1562 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001563 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001564
1565 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001566}
1567
Geoff Langb5348332014-09-02 13:16:34 -04001568gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1569 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1570 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001571{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001572 ASSERT(target == GL_TEXTURE_3D);
1573
Geoff Langb5348332014-09-02 13:16:34 -04001574 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1575 format, imageSize, pixels, mImageArray[level]);
1576 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001577 {
Geoff Langb5348332014-09-02 13:16:34 -04001578 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001579 }
Geoff Langb5348332014-09-02 13:16:34 -04001580
1581 error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
1582 if (error.isError())
1583 {
1584 return error;
1585 }
1586
1587 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001588}
1589
Brandon Jonescef06ff2014-08-05 13:27:48 -07001590void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1591{
1592 UNIMPLEMENTED();
1593}
1594
Brandon Jones78b1acd2014-07-15 15:33:07 -07001595void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1596{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001597 ASSERT(target == GL_TEXTURE_3D);
1598
Brandon Jones78b1acd2014-07-15 15:33:07 -07001599 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1600 // the current level we're copying to is defined (with appropriate format, width & height)
1601 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1602
1603 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1604 {
1605 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1606 mDirtyImages = true;
1607 }
1608 else
1609 {
1610 ensureRenderTarget();
1611
1612 if (isValidLevel(level))
1613 {
1614 updateStorageLevel(level);
1615
1616 gl::Rectangle sourceRect;
1617 sourceRect.x = x;
1618 sourceRect.width = width;
1619 sourceRect.y = y;
1620 sourceRect.height = height;
1621
Jamie Madill856d9d42014-09-18 15:08:49 -04001622 mRenderer->copyImage3D(source, sourceRect,
1623 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1624 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001625 }
1626 }
1627}
1628
Brandon Jonescef06ff2014-08-05 13:27:48 -07001629void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001630{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001631 ASSERT(target == GL_TEXTURE_3D);
1632
Brandon Jones78b1acd2014-07-15 15:33:07 -07001633 for (int level = 0; level < levels; level++)
1634 {
1635 GLsizei levelWidth = std::max(1, width >> level);
1636 GLsizei levelHeight = std::max(1, height >> level);
1637 GLsizei levelDepth = std::max(1, depth >> level);
1638 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1639 }
1640
1641 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1642 {
1643 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1644 }
1645
1646 mImmutable = true;
1647
Jamie Madillc4833262014-09-18 16:18:26 -04001648 bool renderTarget = IsRenderTargetUsage(mUsage);
1649 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001650 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001651}
1652
Brandon Jones6053a522014-07-25 16:22:09 -07001653void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654{
Brandon Jones6053a522014-07-25 16:22:09 -07001655 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656}
1657
Brandon Jones6053a522014-07-25 16:22:09 -07001658void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001659{
Brandon Jones6053a522014-07-25 16:22:09 -07001660 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001661}
1662
Brandon Jones6053a522014-07-25 16:22:09 -07001663
Jamie Madill4aa79e12014-09-29 10:46:14 -04001664void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001665{
1666 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1667 int levelCount = mipLevels();
1668 for (int level = 1; level < levelCount; level++)
1669 {
1670 redefineImage(level, getBaseLevelInternalFormat(),
1671 std::max(getBaseLevelWidth() >> level, 1),
1672 std::max(getBaseLevelHeight() >> level, 1),
1673 std::max(getBaseLevelDepth() >> level, 1));
1674 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001675}
1676
Jamie Madillac7579c2014-09-17 16:59:33 -04001677unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001678{
Jamie Madillc4833262014-09-18 16:18:26 -04001679 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001680}
1681
Jamie Madillac7579c2014-09-17 16:59:33 -04001682RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001683{
1684 // ensure the underlying texture is created
1685 if (!ensureRenderTarget())
1686 {
1687 return NULL;
1688 }
1689
Jamie Madillac7579c2014-09-17 16:59:33 -04001690 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001691 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001692 updateStorage();
1693 }
1694 else
1695 {
1696 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697 }
1698
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001699 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001700}
1701
1702void TextureD3D_3D::initializeStorage(bool renderTarget)
1703{
1704 // Only initialize the first time this texture is used as a render target or shader resource
1705 if (mTexStorage)
1706 {
1707 return;
1708 }
1709
1710 // do not attempt to create storage for nonexistant data
1711 if (!isLevelComplete(0))
1712 {
1713 return;
1714 }
1715
1716 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1717
1718 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1719 ASSERT(mTexStorage);
1720
1721 // flush image data to the storage
1722 updateStorage();
1723}
1724
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001725TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001726{
1727 GLsizei width = getBaseLevelWidth();
1728 GLsizei height = getBaseLevelHeight();
1729 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001730 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001731
1732 ASSERT(width > 0 && height > 0 && depth > 0);
1733
1734 // use existing storage level count, when previously specified by TexStorage*D
1735 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1736
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001737 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001738}
1739
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001740void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741{
1742 SafeDelete(mTexStorage);
1743 mTexStorage = newCompleteTexStorage;
1744 mDirtyImages = true;
1745
1746 // We do not support managed 3D storage, as that is D3D9/ES2-only
1747 ASSERT(!mTexStorage->isManaged());
1748}
1749
1750void TextureD3D_3D::updateStorage()
1751{
1752 ASSERT(mTexStorage != NULL);
1753 GLint storageLevels = mTexStorage->getLevelCount();
1754 for (int level = 0; level < storageLevels; level++)
1755 {
1756 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1757 {
1758 updateStorageLevel(level);
1759 }
1760 }
1761}
1762
1763bool TextureD3D_3D::ensureRenderTarget()
1764{
1765 initializeStorage(true);
1766
1767 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getBaseLevelDepth() > 0)
1768 {
1769 ASSERT(mTexStorage);
1770 if (!mTexStorage->isRenderTarget())
1771 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001772 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001773
Jamie Madill98553e32014-09-30 16:33:50 -04001774 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001775 {
1776 delete newRenderTargetStorage;
1777 return gl::error(GL_OUT_OF_MEMORY, false);
1778 }
1779
1780 setCompleteTexStorage(newRenderTargetStorage);
1781 }
1782 }
1783
1784 return (mTexStorage && mTexStorage->isRenderTarget());
1785}
1786
Brandon Jones78b1acd2014-07-15 15:33:07 -07001787const ImageD3D *TextureD3D_3D::getBaseLevelImage() const
1788{
1789 return mImageArray[0];
1790}
1791
1792bool TextureD3D_3D::isValidLevel(int level) const
1793{
1794 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1795}
1796
1797bool TextureD3D_3D::isLevelComplete(int level) const
1798{
1799 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1800
1801 if (isImmutable())
1802 {
1803 return true;
1804 }
1805
1806 GLsizei width = getBaseLevelWidth();
1807 GLsizei height = getBaseLevelHeight();
1808 GLsizei depth = getBaseLevelDepth();
1809
1810 if (width <= 0 || height <= 0 || depth <= 0)
1811 {
1812 return false;
1813 }
1814
1815 if (level == 0)
1816 {
1817 return true;
1818 }
1819
1820 ImageD3D *levelImage = mImageArray[level];
1821
1822 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1823 {
1824 return false;
1825 }
1826
1827 if (levelImage->getWidth() != std::max(1, width >> level))
1828 {
1829 return false;
1830 }
1831
1832 if (levelImage->getHeight() != std::max(1, height >> level))
1833 {
1834 return false;
1835 }
1836
1837 if (levelImage->getDepth() != std::max(1, depth >> level))
1838 {
1839 return false;
1840 }
1841
1842 return true;
1843}
1844
1845void TextureD3D_3D::updateStorageLevel(int level)
1846{
1847 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1848 ASSERT(isLevelComplete(level));
1849
1850 if (mImageArray[level]->isDirty())
1851 {
1852 commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1853 }
1854}
1855
1856void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1857{
1858 // If there currently is a corresponding storage texture image, it has these parameters
1859 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1860 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1861 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1862 const GLenum storageFormat = getBaseLevelInternalFormat();
1863
1864 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1865
1866 if (mTexStorage)
1867 {
1868 const int storageLevels = mTexStorage->getLevelCount();
1869
1870 if ((level >= storageLevels && storageLevels != 0) ||
1871 width != storageWidth ||
1872 height != storageHeight ||
1873 depth != storageDepth ||
1874 internalformat != storageFormat) // Discard mismatched storage
1875 {
1876 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1877 {
1878 mImageArray[i]->markDirty();
1879 }
1880
1881 SafeDelete(mTexStorage);
1882 mDirtyImages = true;
1883 }
1884 }
1885}
1886
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001887gl::Error TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001888{
1889 if (isValidLevel(level))
1890 {
1891 ImageD3D *image = mImageArray[level];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001892 gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
1893 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001894 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001895 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001896 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001897
1898 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001899 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001900
1901 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001902}
1903
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001904gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1905{
1906 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1907 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1908}
Brandon Jones142ec422014-07-16 10:31:30 -07001909
Jamie Madillcb83dc12014-09-29 10:46:12 -04001910gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1911{
1912 // The "layer" here does not apply to 3D images. We use one Image per mip.
1913 return gl::ImageIndex::Make3D(mip);
1914}
1915
Brandon Jones142ec422014-07-16 10:31:30 -07001916TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001917 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001918{
1919 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1920 {
1921 mLayerCounts[level] = 0;
1922 mImageArray[level] = NULL;
1923 }
1924}
1925
1926TextureD3D_2DArray::~TextureD3D_2DArray()
1927{
Austin Kinross69822602014-08-12 15:51:37 -07001928 // Delete the Images before the TextureStorage.
1929 // Images might be relying on the TextureStorage for some of their data.
1930 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones142ec422014-07-16 10:31:30 -07001931 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001932 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001933}
1934
Brandon Jones142ec422014-07-16 10:31:30 -07001935Image *TextureD3D_2DArray::getImage(int level, int layer) const
1936{
1937 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1938 ASSERT(layer < mLayerCounts[level]);
1939 return mImageArray[level][layer];
1940}
1941
Jamie Madillfeda4d22014-09-17 13:03:29 -04001942Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1943{
1944 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1945 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1946 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1947 return mImageArray[index.mipIndex][index.layerIndex];
1948}
1949
Brandon Jones142ec422014-07-16 10:31:30 -07001950GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1951{
1952 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1953 return mLayerCounts[level];
1954}
1955
Brandon Jones142ec422014-07-16 10:31:30 -07001956GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1957{
1958 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1959}
1960
1961GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1962{
1963 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1964}
1965
1966GLsizei TextureD3D_2DArray::getLayers(GLint level) const
1967{
1968 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS) ? mLayerCounts[level] : 0;
1969}
1970
1971GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1972{
1973 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1974}
1975
1976bool TextureD3D_2DArray::isDepth(GLint level) const
1977{
Geoff Lang5d601382014-07-22 15:14:06 -04001978 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001979}
1980
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001981gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1982 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1983 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001984{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001985 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1986
Geoff Lang5d601382014-07-22 15:14:06 -04001987 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1988
Brandon Jones142ec422014-07-16 10:31:30 -07001989 redefineImage(level, sizedInternalFormat, width, height, depth);
1990
Geoff Lang5d601382014-07-22 15:14:06 -04001991 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1992 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001993
1994 for (int i = 0; i < depth; i++)
1995 {
1996 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001997 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1998 if (error.isError())
1999 {
2000 return error;
2001 }
Brandon Jones142ec422014-07-16 10:31:30 -07002002 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002003
2004 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002005}
2006
Geoff Langb5348332014-09-02 13:16:34 -04002007gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2008 GLsizei width, GLsizei height, GLsizei depth,
2009 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002010{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002011 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2012
Brandon Jones142ec422014-07-16 10:31:30 -07002013 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2014 redefineImage(level, format, width, height, depth);
2015
Geoff Lang5d601382014-07-22 15:14:06 -04002016 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2017 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002018
2019 for (int i = 0; i < depth; i++)
2020 {
2021 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002022 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2023 if (error.isError())
2024 {
2025 return error;
2026 }
Brandon Jones142ec422014-07-16 10:31:30 -07002027 }
Geoff Langb5348332014-09-02 13:16:34 -04002028
2029 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002030}
2031
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002032gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2033 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2034 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002035{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002036 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2037
Geoff Lang5d601382014-07-22 15:14:06 -04002038 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2039 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002040
2041 for (int i = 0; i < depth; i++)
2042 {
2043 int layer = zoffset + i;
2044 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2045
Jamie Madillfeda4d22014-09-17 13:03:29 -04002046 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002047 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
2048 layerPixels, index);
2049 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002050 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002051 return error;
2052 }
2053
2054 error = commitRect(level, xoffset, yoffset, layer, width, height);
2055 if (error.isError())
2056 {
2057 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002058 }
2059 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002060
2061 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002062}
2063
Geoff Langb5348332014-09-02 13:16:34 -04002064gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2065 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2066 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002067{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002068 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2069
Geoff Lang5d601382014-07-22 15:14:06 -04002070 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2071 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002072
2073 for (int i = 0; i < depth; i++)
2074 {
2075 int layer = zoffset + i;
2076 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2077
Geoff Langb5348332014-09-02 13:16:34 -04002078 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2079 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002080 {
Geoff Langb5348332014-09-02 13:16:34 -04002081 return error;
2082 }
2083
2084 error = commitRect(level, xoffset, yoffset, layer, width, height);
2085 if (error.isError())
2086 {
2087 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002088 }
2089 }
Geoff Langb5348332014-09-02 13:16:34 -04002090
2091 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002092}
2093
Brandon Jonescef06ff2014-08-05 13:27:48 -07002094void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2095{
2096 UNIMPLEMENTED();
2097}
2098
Brandon Jones142ec422014-07-16 10:31:30 -07002099void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2100{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002101 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2102
Brandon Jones142ec422014-07-16 10:31:30 -07002103 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2104 // the current level we're copying to is defined (with appropriate format, width & height)
2105 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2106
2107 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2108 {
2109 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2110 mDirtyImages = true;
2111 }
2112 else
2113 {
2114 ensureRenderTarget();
2115
2116 if (isValidLevel(level))
2117 {
2118 updateStorageLevel(level);
2119
2120 gl::Rectangle sourceRect;
2121 sourceRect.x = x;
2122 sourceRect.width = width;
2123 sourceRect.y = y;
2124 sourceRect.height = height;
2125
Jamie Madill856d9d42014-09-18 15:08:49 -04002126 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2127 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002128 }
2129 }
2130}
2131
Brandon Jonescef06ff2014-08-05 13:27:48 -07002132void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002133{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002134 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2135
Brandon Jones142ec422014-07-16 10:31:30 -07002136 deleteImages();
2137
2138 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2139 {
2140 GLsizei levelWidth = std::max(1, width >> level);
2141 GLsizei levelHeight = std::max(1, height >> level);
2142
2143 mLayerCounts[level] = (level < levels ? depth : 0);
2144
2145 if (mLayerCounts[level] > 0)
2146 {
2147 // Create new images for this level
2148 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2149
2150 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2151 {
2152 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2153 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2154 levelHeight, 1, true);
2155 }
2156 }
2157 }
2158
2159 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002160
2161 bool renderTarget = IsRenderTargetUsage(mUsage);
2162 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002163 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002164}
2165
Brandon Jones6053a522014-07-25 16:22:09 -07002166void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002167{
Brandon Jones6053a522014-07-25 16:22:09 -07002168 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002169}
2170
Brandon Jones6053a522014-07-25 16:22:09 -07002171void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002172{
Brandon Jones6053a522014-07-25 16:22:09 -07002173 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002174}
2175
Brandon Jones6053a522014-07-25 16:22:09 -07002176
Jamie Madill4aa79e12014-09-29 10:46:14 -04002177void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002178{
2179 int baseWidth = getBaseLevelWidth();
2180 int baseHeight = getBaseLevelHeight();
2181 int baseDepth = getBaseLevelDepth();
2182 GLenum baseFormat = getBaseLevelInternalFormat();
2183
2184 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2185 int levelCount = mipLevels();
2186 for (int level = 1; level < levelCount; level++)
2187 {
2188 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2189 }
Brandon Jones142ec422014-07-16 10:31:30 -07002190}
2191
Jamie Madillac7579c2014-09-17 16:59:33 -04002192unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002193{
Jamie Madillc4833262014-09-18 16:18:26 -04002194 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002195}
2196
Jamie Madillac7579c2014-09-17 16:59:33 -04002197RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002198{
2199 // ensure the underlying texture is created
2200 if (!ensureRenderTarget())
2201 {
2202 return NULL;
2203 }
2204
Jamie Madillac7579c2014-09-17 16:59:33 -04002205 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002206 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002207}
2208
2209void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2210{
2211 // Only initialize the first time this texture is used as a render target or shader resource
2212 if (mTexStorage)
2213 {
2214 return;
2215 }
2216
2217 // do not attempt to create storage for nonexistant data
2218 if (!isLevelComplete(0))
2219 {
2220 return;
2221 }
2222
2223 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2224
2225 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2226 ASSERT(mTexStorage);
2227
2228 // flush image data to the storage
2229 updateStorage();
2230}
2231
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002232TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002233{
2234 GLsizei width = getBaseLevelWidth();
2235 GLsizei height = getBaseLevelHeight();
2236 GLsizei depth = getLayers(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002237 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002238
2239 ASSERT(width > 0 && height > 0 && depth > 0);
2240
2241 // use existing storage level count, when previously specified by TexStorage*D
2242 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2243
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002244 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002245}
2246
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002247void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002248{
2249 SafeDelete(mTexStorage);
2250 mTexStorage = newCompleteTexStorage;
2251 mDirtyImages = true;
2252
2253 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2254 ASSERT(!mTexStorage->isManaged());
2255}
2256
2257void TextureD3D_2DArray::updateStorage()
2258{
2259 ASSERT(mTexStorage != NULL);
2260 GLint storageLevels = mTexStorage->getLevelCount();
2261 for (int level = 0; level < storageLevels; level++)
2262 {
2263 if (isLevelComplete(level))
2264 {
2265 updateStorageLevel(level);
2266 }
2267 }
2268}
2269
2270bool TextureD3D_2DArray::ensureRenderTarget()
2271{
2272 initializeStorage(true);
2273
2274 if (getBaseLevelWidth() > 0 && getBaseLevelHeight() > 0 && getLayers(0) > 0)
2275 {
2276 ASSERT(mTexStorage);
2277 if (!mTexStorage->isRenderTarget())
2278 {
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002279 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
Brandon Jones142ec422014-07-16 10:31:30 -07002280
Jamie Madill98553e32014-09-30 16:33:50 -04002281 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002282 {
2283 delete newRenderTargetStorage;
2284 return gl::error(GL_OUT_OF_MEMORY, false);
2285 }
2286
2287 setCompleteTexStorage(newRenderTargetStorage);
2288 }
2289 }
2290
2291 return (mTexStorage && mTexStorage->isRenderTarget());
2292}
2293
2294const ImageD3D *TextureD3D_2DArray::getBaseLevelImage() const
2295{
2296 return (mLayerCounts[0] > 0 ? mImageArray[0][0] : NULL);
2297}
2298
Brandon Jones142ec422014-07-16 10:31:30 -07002299bool TextureD3D_2DArray::isValidLevel(int level) const
2300{
2301 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2302}
2303
2304bool TextureD3D_2DArray::isLevelComplete(int level) const
2305{
2306 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2307
2308 if (isImmutable())
2309 {
2310 return true;
2311 }
2312
2313 GLsizei width = getBaseLevelWidth();
2314 GLsizei height = getBaseLevelHeight();
2315 GLsizei layers = getLayers(0);
2316
2317 if (width <= 0 || height <= 0 || layers <= 0)
2318 {
2319 return false;
2320 }
2321
2322 if (level == 0)
2323 {
2324 return true;
2325 }
2326
2327 if (getInternalFormat(level) != getInternalFormat(0))
2328 {
2329 return false;
2330 }
2331
2332 if (getWidth(level) != std::max(1, width >> level))
2333 {
2334 return false;
2335 }
2336
2337 if (getHeight(level) != std::max(1, height >> level))
2338 {
2339 return false;
2340 }
2341
2342 if (getLayers(level) != layers)
2343 {
2344 return false;
2345 }
2346
2347 return true;
2348}
2349
2350void TextureD3D_2DArray::updateStorageLevel(int level)
2351{
2352 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2353 ASSERT(isLevelComplete(level));
2354
2355 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2356 {
2357 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2358 if (mImageArray[level][layer]->isDirty())
2359 {
2360 commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
2361 }
2362 }
2363}
2364
2365void TextureD3D_2DArray::deleteImages()
2366{
2367 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2368 {
2369 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2370 {
2371 delete mImageArray[level][layer];
2372 }
2373 delete[] mImageArray[level];
2374 mImageArray[level] = NULL;
2375 mLayerCounts[level] = 0;
2376 }
2377}
2378
2379void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2380{
2381 // If there currently is a corresponding storage texture image, it has these parameters
2382 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2383 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2384 const int storageDepth = getLayers(0);
2385 const GLenum storageFormat = getBaseLevelInternalFormat();
2386
2387 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2388 {
2389 delete mImageArray[level][layer];
2390 }
2391 delete[] mImageArray[level];
2392 mImageArray[level] = NULL;
2393 mLayerCounts[level] = depth;
2394
2395 if (depth > 0)
2396 {
2397 mImageArray[level] = new ImageD3D*[depth]();
2398
2399 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2400 {
2401 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2402 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2403 }
2404 }
2405
2406 if (mTexStorage)
2407 {
2408 const int storageLevels = mTexStorage->getLevelCount();
2409
2410 if ((level >= storageLevels && storageLevels != 0) ||
2411 width != storageWidth ||
2412 height != storageHeight ||
2413 depth != storageDepth ||
2414 internalformat != storageFormat) // Discard mismatched storage
2415 {
2416 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2417 {
2418 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2419 {
2420 mImageArray[level][layer]->markDirty();
2421 }
2422 }
2423
2424 delete mTexStorage;
2425 mTexStorage = NULL;
2426 mDirtyImages = true;
2427 }
2428 }
2429}
2430
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002431gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
Brandon Jones142ec422014-07-16 10:31:30 -07002432{
2433 if (isValidLevel(level) && layerTarget < getLayers(level))
2434 {
2435 ImageD3D *image = mImageArray[level][layerTarget];
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002436 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
2437 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002438 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002439 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002440 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002441
2442 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002443 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002444
2445 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002446}
2447
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002448gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2449{
2450 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2451}
2452
Jamie Madillcb83dc12014-09-29 10:46:12 -04002453gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2454{
2455 return gl::ImageIndex::Make2DArray(mip, layer);
2456}
2457
Brandon Jones78b1acd2014-07-15 15:33:07 -07002458}