blob: 9991842a38f5c91cfbab2d69409c78b8cd4426b6 [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();
Jacek Cabana5521de2014-10-01 17:23:46 +0200139 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700140 // 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
Jamie Madille6b6da02014-10-02 11:03:14 -0400158 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
159 error = commitRegion(index, region);
160 if (error.isError())
161 {
162 return error;
163 }
164
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 mDirtyImages = true;
166 }
167
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400168 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700169}
170
Geoff Langb5348332014-09-02 13:16:34 -0400171gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700172{
173 if (pixels != NULL)
174 {
Geoff Langb5348332014-09-02 13:16:34 -0400175 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
176 if (error.isError())
177 {
178 return error;
179 }
180
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181 mDirtyImages = true;
182 }
Geoff Langb5348332014-09-02 13:16:34 -0400183
184 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700185}
186
Geoff Langb5348332014-09-02 13:16:34 -0400187gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700188 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700189{
190 if (pixels != NULL)
191 {
Geoff Langb5348332014-09-02 13:16:34 -0400192 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
193 if (error.isError())
194 {
195 return error;
196 }
197
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198 mDirtyImages = true;
199 }
200
Geoff Langb5348332014-09-02 13:16:34 -0400201 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700202}
203
204bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
205{
206 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
207}
208
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400209gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
210 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400212 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700213 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
214 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400215 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700216 }
217
218 // In order to perform the fast copy through the shader, we must have the right format, and be able
219 // to create a render target.
220 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
221
Jacek Cabana5521de2014-10-01 17:23:46 +0200222 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700223
Geoff Langae5122c2014-08-27 14:08:43 -0400224 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
225 if (error.isError())
226 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400227 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400228 }
229
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400230 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
233GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
234{
235 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
236 {
237 // Maximum number of levels
238 return gl::log2(std::max(std::max(width, height), depth)) + 1;
239 }
240 else
241 {
242 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
243 return 1;
244 }
245}
246
247int TextureD3D::mipLevels() const
248{
249 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
250}
251
Jamie Madill98553e32014-09-30 16:33:50 -0400252TextureStorage *TextureD3D::getStorage()
253{
254 return mTexStorage;
255}
256
Jamie Madill3269bcb2014-09-30 16:33:52 -0400257Image *TextureD3D::getBaseLevelImage() const
258{
259 return getImage(getImageIndex(0, 0));
260}
261
Jamie Madill4aa79e12014-09-29 10:46:14 -0400262void TextureD3D::generateMipmaps()
263{
264 // Set up proper image sizes.
265 initMipmapsImages();
266
267 // We know that all layers have the same dimension, for the texture to be complete
268 GLint layerCount = static_cast<GLint>(getLayerCount(0));
269 GLint mipCount = mipLevels();
270
271 // The following will create and initialize the storage, or update it if it exists
272 TextureStorage *storage = getNativeTexture();
273
274 bool renderableStorage = (storage && storage->isRenderTarget());
275
276 for (GLint layer = 0; layer < layerCount; ++layer)
277 {
278 for (GLint mip = 1; mip < mipCount; ++mip)
279 {
280 ASSERT(getLayerCount(mip) == layerCount);
281
282 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
283 gl::ImageIndex destIndex = getImageIndex(mip, layer);
284
285 if (renderableStorage)
286 {
287 // GPU-side mipmapping
288 storage->generateMipmap(sourceIndex, destIndex);
289 }
290 else
291 {
292 // CPU-side mipmapping
293 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
294 }
295 }
296 }
297}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700298
Jamie Madill135570a2014-09-30 16:33:51 -0400299bool TextureD3D::isBaseImageZeroSize() const
300{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400301 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400302
303 if (!baseImage || baseImage->getWidth() <= 0)
304 {
305 return true;
306 }
307
308 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
309 {
310 return true;
311 }
312
313 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
314 {
315 return true;
316 }
317
318 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
319 {
320 return true;
321 }
322
323 return false;
324}
325
326bool TextureD3D::ensureRenderTarget()
327{
328 initializeStorage(true);
329
330 if (!isBaseImageZeroSize())
331 {
332 ASSERT(mTexStorage);
333 if (!mTexStorage->isRenderTarget())
334 {
335 TextureStorage *newRenderTargetStorage = createCompleteStorage(true);
336
337 if (mTexStorage->copyToStorage(newRenderTargetStorage).isError())
338 {
339 delete newRenderTargetStorage;
340 return gl::error(GL_OUT_OF_MEMORY, false);
341 }
342
343 setCompleteTexStorage(newRenderTargetStorage);
344 }
345 }
346
347 return (mTexStorage && mTexStorage->isRenderTarget());
348}
349
Brandon Jones78b1acd2014-07-15 15:33:07 -0700350TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400351 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700352{
353 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
354 {
355 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
356 }
357}
358
359TextureD3D_2D::~TextureD3D_2D()
360{
Austin Kinross69822602014-08-12 15:51:37 -0700361 // Delete the Images before the TextureStorage.
362 // Images might be relying on the TextureStorage for some of their data.
363 // 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 -0700364 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
365 {
366 delete mImageArray[i];
367 }
Austin Kinross69822602014-08-12 15:51:37 -0700368
369 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700370}
371
Brandon Jonescef06ff2014-08-05 13:27:48 -0700372Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700373{
374 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700375 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700376 return mImageArray[level];
377}
378
Jamie Madillfeda4d22014-09-17 13:03:29 -0400379Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
380{
381 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400382 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400383 ASSERT(index.type == GL_TEXTURE_2D);
384 return mImageArray[index.mipIndex];
385}
386
Brandon Jonescef06ff2014-08-05 13:27:48 -0700387GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700388{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700389 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
390 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700391}
392
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700393GLsizei TextureD3D_2D::getWidth(GLint level) const
394{
395 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
396 return mImageArray[level]->getWidth();
397 else
398 return 0;
399}
400
401GLsizei TextureD3D_2D::getHeight(GLint level) const
402{
403 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
404 return mImageArray[level]->getHeight();
405 else
406 return 0;
407}
408
409GLenum TextureD3D_2D::getInternalFormat(GLint level) const
410{
411 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
412 return mImageArray[level]->getInternalFormat();
413 else
414 return GL_NONE;
415}
416
417GLenum TextureD3D_2D::getActualFormat(GLint level) const
418{
419 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
420 return mImageArray[level]->getActualFormat();
421 else
422 return GL_NONE;
423}
424
425bool TextureD3D_2D::isDepth(GLint level) const
426{
Geoff Lang5d601382014-07-22 15:14:06 -0400427 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700428}
429
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400430gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
431 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
432 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700433{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700434 ASSERT(target == GL_TEXTURE_2D && depth == 1);
435
Geoff Lang5d601382014-07-22 15:14:06 -0400436 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
437
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700438 bool fastUnpacked = false;
439
Brandon Jonescef06ff2014-08-05 13:27:48 -0700440 redefineImage(level, sizedInternalFormat, width, height);
441
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442 // Attempt a fast gpu copy of the pixel data to the surface
443 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
444 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400445 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
446
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700447 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -0400448 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700449 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
450
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400451 if (destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700452 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400453 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
454 if (error.isError())
455 {
456 return error;
457 }
458
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700459 // Ensure we don't overwrite our newly initialized data
460 mImageArray[level]->markClean();
461
462 fastUnpacked = true;
463 }
464 }
465
466 if (!fastUnpacked)
467 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400468 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
469 if (error.isError())
470 {
471 return error;
472 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700473 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400474
475 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700476}
477
Geoff Langb5348332014-09-02 13:16:34 -0400478gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
479 GLsizei width, GLsizei height, GLsizei depth,
480 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700481{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700482 ASSERT(target == GL_TEXTURE_2D && depth == 1);
483
484 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
485 redefineImage(level, format, width, height);
486
Geoff Langb5348332014-09-02 13:16:34 -0400487 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700488}
489
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400490gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
491 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
492 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700494 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
495
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700496 bool fastUnpacked = false;
497
Jamie Madillac7579c2014-09-17 16:59:33 -0400498 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400499 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700500 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
501 {
Jamie Madillac7579c2014-09-17 16:59:33 -0400502 RenderTarget *renderTarget = getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700503
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400504 if (renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700505 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400506 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
507 if (error.isError())
508 {
509 return error;
510 }
511
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700512 // Ensure we don't overwrite our newly initialized data
513 mImageArray[level]->markClean();
514
515 fastUnpacked = true;
516 }
517 }
518
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400519 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700520 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400521 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
522 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700523 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400524
525 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700526}
527
Geoff Langb5348332014-09-02 13:16:34 -0400528gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
529 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
530 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700531{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
533
Geoff Langb5348332014-09-02 13:16:34 -0400534 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
535 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536 {
Geoff Langb5348332014-09-02 13:16:34 -0400537 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538 }
Geoff Langb5348332014-09-02 13:16:34 -0400539
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400540 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
541 gl::Box region(xoffset, yoffset, 0, width, height, 1);
542 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543}
544
Brandon Jonescef06ff2014-08-05 13:27:48 -0700545void 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 -0700546{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700547 ASSERT(target == GL_TEXTURE_2D);
548
549 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
550 redefineImage(level, sizedInternalFormat, width, height);
551
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552 if (!mImageArray[level]->isRenderableFormat())
553 {
554 mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
555 mDirtyImages = true;
556 }
557 else
558 {
559 ensureRenderTarget();
560 mImageArray[level]->markClean();
561
562 if (width != 0 && height != 0 && isValidLevel(level))
563 {
564 gl::Rectangle sourceRect;
565 sourceRect.x = x;
566 sourceRect.width = width;
567 sourceRect.y = y;
568 sourceRect.height = height;
569
Jamie Madill856d9d42014-09-18 15:08:49 -0400570 mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700571 }
572 }
573}
574
575void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
576{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700577 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
578
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
580 // the current level we're copying to is defined (with appropriate format, width & height)
581 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
582
583 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
584 {
585 mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
586 mDirtyImages = true;
587 }
588 else
589 {
590 ensureRenderTarget();
591
592 if (isValidLevel(level))
593 {
594 updateStorageLevel(level);
595
596 gl::Rectangle sourceRect;
597 sourceRect.x = x;
598 sourceRect.width = width;
599 sourceRect.y = y;
600 sourceRect.height = height;
601
Jamie Madill856d9d42014-09-18 15:08:49 -0400602 mRenderer->copyImage2D(source, sourceRect,
603 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
604 xoffset, yoffset, mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700605 }
606 }
607}
608
Brandon Jonescef06ff2014-08-05 13:27:48 -0700609void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700610{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700611 ASSERT(target == GL_TEXTURE_2D && depth == 1);
612
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 for (int level = 0; level < levels; level++)
614 {
615 GLsizei levelWidth = std::max(1, width >> level);
616 GLsizei levelHeight = std::max(1, height >> level);
617 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
618 }
619
620 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
621 {
622 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
623 }
624
625 mImmutable = true;
626
Jamie Madillc4833262014-09-18 16:18:26 -0400627 bool renderTarget = IsRenderTargetUsage(mUsage);
628 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400629 setCompleteTexStorage(storage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630}
631
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632void TextureD3D_2D::bindTexImage(egl::Surface *surface)
633{
634 GLenum internalformat = surface->getFormat();
635
636 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
637
638 if (mTexStorage)
639 {
640 SafeDelete(mTexStorage);
641 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400642
643 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700644
645 mDirtyImages = true;
646}
647
648void TextureD3D_2D::releaseTexImage()
649{
650 if (mTexStorage)
651 {
652 SafeDelete(mTexStorage);
653 }
654
655 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
656 {
657 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
658 }
659}
660
Jamie Madill4aa79e12014-09-29 10:46:14 -0400661void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700663 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700664 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700665 for (int level = 1; level < levelCount; level++)
666 {
667 redefineImage(level, getBaseLevelInternalFormat(),
668 std::max(getBaseLevelWidth() >> level, 1),
669 std::max(getBaseLevelHeight() >> level, 1));
670 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700671}
672
Jamie Madillac7579c2014-09-17 16:59:33 -0400673unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674{
Jamie Madillac7579c2014-09-17 16:59:33 -0400675 ASSERT(!index.hasLayer());
Jamie Madillc4833262014-09-18 16:18:26 -0400676 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677}
678
Jamie Madillac7579c2014-09-17 16:59:33 -0400679RenderTarget *TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700680{
Jamie Madillac7579c2014-09-17 16:59:33 -0400681 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700682
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683 // ensure the underlying texture is created
684 if (!ensureRenderTarget())
685 {
686 return NULL;
687 }
688
Jamie Madillac7579c2014-09-17 16:59:33 -0400689 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400690 return mTexStorage->getRenderTarget(index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700691}
692
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700693bool TextureD3D_2D::isValidLevel(int level) const
694{
695 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
696}
697
698bool TextureD3D_2D::isLevelComplete(int level) const
699{
700 if (isImmutable())
701 {
702 return true;
703 }
704
Brandon Jones78b1acd2014-07-15 15:33:07 -0700705 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700706
707 GLsizei width = baseImage->getWidth();
708 GLsizei height = baseImage->getHeight();
709
710 if (width <= 0 || height <= 0)
711 {
712 return false;
713 }
714
715 // The base image level is complete if the width and height are positive
716 if (level == 0)
717 {
718 return true;
719 }
720
721 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700722 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700723
724 if (image->getInternalFormat() != baseImage->getInternalFormat())
725 {
726 return false;
727 }
728
729 if (image->getWidth() != std::max(1, width >> level))
730 {
731 return false;
732 }
733
734 if (image->getHeight() != std::max(1, height >> level))
735 {
736 return false;
737 }
738
739 return true;
740}
741
742// Constructs a native texture resource from the texture images
743void TextureD3D_2D::initializeStorage(bool renderTarget)
744{
745 // Only initialize the first time this texture is used as a render target or shader resource
746 if (mTexStorage)
747 {
748 return;
749 }
750
751 // do not attempt to create storage for nonexistant data
752 if (!isLevelComplete(0))
753 {
754 return;
755 }
756
757 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
758
759 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
760 ASSERT(mTexStorage);
761
762 // flush image data to the storage
763 updateStorage();
764}
765
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400766TextureStorage *TextureD3D_2D::createCompleteStorage(bool renderTarget) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700767{
768 GLsizei width = getBaseLevelWidth();
769 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400770 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700771
772 ASSERT(width > 0 && height > 0);
773
774 // use existing storage level count, when previously specified by TexStorage*D
775 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
776
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400777 return mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700778}
779
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400780void TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700781{
782 SafeDelete(mTexStorage);
783 mTexStorage = newCompleteTexStorage;
784
785 if (mTexStorage && mTexStorage->isManaged())
786 {
787 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
788 {
Jamie Madill856d9d42014-09-18 15:08:49 -0400789 mImageArray[level]->setManagedSurface2D(mTexStorage, level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700790 }
791 }
792
793 mDirtyImages = true;
794}
795
796void TextureD3D_2D::updateStorage()
797{
798 ASSERT(mTexStorage != NULL);
799 GLint storageLevels = mTexStorage->getLevelCount();
800 for (int level = 0; level < storageLevels; level++)
801 {
802 if (mImageArray[level]->isDirty() && isLevelComplete(level))
803 {
804 updateStorageLevel(level);
805 }
806 }
807}
808
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809void TextureD3D_2D::updateStorageLevel(int level)
810{
811 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
812 ASSERT(isLevelComplete(level));
813
814 if (mImageArray[level]->isDirty())
815 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400816 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
817 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
818 commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700819 }
820}
821
822void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
823{
824 // If there currently is a corresponding storage texture image, it has these parameters
825 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
826 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
827 const GLenum storageFormat = getBaseLevelInternalFormat();
828
829 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
830
831 if (mTexStorage)
832 {
833 const int storageLevels = mTexStorage->getLevelCount();
834
835 if ((level >= storageLevels && storageLevels != 0) ||
836 width != storageWidth ||
837 height != storageHeight ||
838 internalformat != storageFormat) // Discard mismatched storage
839 {
840 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
841 {
842 mImageArray[i]->markDirty();
843 }
844
845 SafeDelete(mTexStorage);
846 mDirtyImages = true;
847 }
848 }
849}
850
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400851gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700852{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400853 ASSERT(!index.hasLayer());
854 GLint level = index.mipIndex;
855
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700856 if (isValidLevel(level))
857 {
Brandon Jones78b1acd2014-07-15 15:33:07 -0700858 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400859 gl::Error error = image->copyToStorage2D(mTexStorage, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400860 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700861 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400862 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400864
865 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400867
868 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869}
870
Jamie Madillef4ac5b2014-09-29 10:46:11 -0400871gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
872{
873 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
874}
Brandon Jones0511e802014-07-14 16:27:26 -0700875
Jamie Madillcb83dc12014-09-29 10:46:12 -0400876gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
877{
878 // "layer" does not apply to 2D Textures.
879 return gl::ImageIndex::Make2D(mip);
880}
881
Brandon Jones78b1acd2014-07-15 15:33:07 -0700882TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400883 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -0700884{
885 for (int i = 0; i < 6; i++)
886 {
887 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
888 {
889 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
890 }
891 }
892}
893
894TextureD3D_Cube::~TextureD3D_Cube()
895{
Austin Kinross69822602014-08-12 15:51:37 -0700896 // Delete the Images before the TextureStorage.
897 // Images might be relying on the TextureStorage for some of their data.
898 // 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 -0700899 for (int i = 0; i < 6; i++)
900 {
901 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
902 {
903 SafeDelete(mImageArray[i][j]);
904 }
905 }
Austin Kinross69822602014-08-12 15:51:37 -0700906
907 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -0700908}
909
Brandon Jonescef06ff2014-08-05 13:27:48 -0700910Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700911{
912 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700913 ASSERT(layer < 6);
914 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -0700915}
916
Jamie Madillfeda4d22014-09-17 13:03:29 -0400917Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
918{
919 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
920 ASSERT(index.layerIndex < 6);
921 return mImageArray[index.layerIndex][index.mipIndex];
922}
923
Brandon Jonescef06ff2014-08-05 13:27:48 -0700924GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -0700925{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700926 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
927 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -0700928}
929
Brandon Jonescef06ff2014-08-05 13:27:48 -0700930GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700931{
932 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -0700933 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -0700934 else
935 return GL_NONE;
936}
937
Brandon Jonescef06ff2014-08-05 13:27:48 -0700938bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -0700939{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700940 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -0700941}
942
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400943gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
944 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
945 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700946{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700947 ASSERT(depth == 1);
948
949 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -0400950 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Brandon Jones0511e802014-07-14 16:27:26 -0700951
952 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
953
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400954 return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700955}
956
Geoff Langb5348332014-09-02 13:16:34 -0400957gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
958 GLsizei width, GLsizei height, GLsizei depth,
959 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700960{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700961 ASSERT(depth == 1);
962
Brandon Jones0511e802014-07-14 16:27:26 -0700963 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -0700964 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
965
Brandon Jones0511e802014-07-14 16:27:26 -0700966 redefineImage(faceIndex, level, format, width, height);
967
Geoff Langb5348332014-09-02 13:16:34 -0400968 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -0700969}
970
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400971gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
972 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
973 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700974{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700975 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -0400976 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -0400977 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -0700978}
979
Geoff Langb5348332014-09-02 13:16:34 -0400980gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
981 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
982 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -0700983{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700984 ASSERT(depth == 1 && zoffset == 0);
985
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400986 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700987
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400988 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -0400989 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -0700990 {
Geoff Langb5348332014-09-02 13:16:34 -0400991 return error;
Brandon Jones0511e802014-07-14 16:27:26 -0700992 }
Geoff Langb5348332014-09-02 13:16:34 -0400993
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400994 gl::Box region(xoffset, yoffset, 0, width, height, 1);
995 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -0700996}
997
998void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
999{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001000 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001001 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1002
Brandon Jones0511e802014-07-14 16:27:26 -07001003 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1004
1005 if (!mImageArray[faceIndex][level]->isRenderableFormat())
1006 {
1007 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1008 mDirtyImages = true;
1009 }
1010 else
1011 {
1012 ensureRenderTarget();
1013 mImageArray[faceIndex][level]->markClean();
1014
1015 ASSERT(width == height);
1016
1017 if (width > 0 && isValidFaceLevel(faceIndex, level))
1018 {
1019 gl::Rectangle sourceRect;
1020 sourceRect.x = x;
1021 sourceRect.width = width;
1022 sourceRect.y = y;
1023 sourceRect.height = height;
1024
Jamie Madill856d9d42014-09-18 15:08:49 -04001025 mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001026 }
1027 }
1028}
1029
1030void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1031{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001032 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001033
1034 // We can only make our texture storage to a render target if the level we're copying *to* is complete
1035 // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
1036 // rely on the "getBaseLevel*" methods reliably otherwise.
1037 bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
1038
1039 if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1040 {
1041 mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
1042 mDirtyImages = true;
1043 }
1044 else
1045 {
1046 ensureRenderTarget();
1047
1048 if (isValidFaceLevel(faceIndex, level))
1049 {
1050 updateStorageFaceLevel(faceIndex, level);
1051
1052 gl::Rectangle sourceRect;
1053 sourceRect.x = x;
1054 sourceRect.width = width;
1055 sourceRect.y = y;
1056 sourceRect.height = height;
1057
Jamie Madill856d9d42014-09-18 15:08:49 -04001058 mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1059 xoffset, yoffset, mTexStorage, target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001060 }
1061 }
1062}
1063
Brandon Jonescef06ff2014-08-05 13:27:48 -07001064void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001065{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001066 ASSERT(width == height);
1067 ASSERT(depth == 1);
1068
Brandon Jones0511e802014-07-14 16:27:26 -07001069 for (int level = 0; level < levels; level++)
1070 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001071 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001072 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1073 {
1074 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1075 }
1076 }
1077
1078 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1079 {
1080 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1081 {
1082 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1083 }
1084 }
1085
1086 mImmutable = true;
1087
Jamie Madillc4833262014-09-18 16:18:26 -04001088 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001089 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
1090 setCompleteTexStorage(storage);
Brandon Jones0511e802014-07-14 16:27:26 -07001091}
1092
Brandon Jones0511e802014-07-14 16:27:26 -07001093// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1094bool TextureD3D_Cube::isCubeComplete() const
1095{
1096 int baseWidth = getBaseLevelWidth();
1097 int baseHeight = getBaseLevelHeight();
1098 GLenum baseFormat = getBaseLevelInternalFormat();
1099
1100 if (baseWidth <= 0 || baseWidth != baseHeight)
1101 {
1102 return false;
1103 }
1104
1105 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1106 {
1107 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1108
1109 if (faceBaseImage.getWidth() != baseWidth ||
1110 faceBaseImage.getHeight() != baseHeight ||
1111 faceBaseImage.getInternalFormat() != baseFormat )
1112 {
1113 return false;
1114 }
1115 }
1116
1117 return true;
1118}
1119
Brandon Jones6053a522014-07-25 16:22:09 -07001120void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1121{
1122 UNREACHABLE();
1123}
1124
1125void TextureD3D_Cube::releaseTexImage()
1126{
1127 UNREACHABLE();
1128}
1129
1130
Jamie Madill4aa79e12014-09-29 10:46:14 -04001131void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
1133 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1134 int levelCount = mipLevels();
1135 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1136 {
1137 for (int level = 1; level < levelCount; level++)
1138 {
1139 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1140 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1141 }
1142 }
Brandon Jones0511e802014-07-14 16:27:26 -07001143}
1144
Jamie Madillac7579c2014-09-17 16:59:33 -04001145unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001146{
Jamie Madillc4833262014-09-18 16:18:26 -04001147 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001148}
1149
Jamie Madillac7579c2014-09-17 16:59:33 -04001150RenderTarget *TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001151{
Jamie Madillac7579c2014-09-17 16:59:33 -04001152 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001153
1154 // ensure the underlying texture is created
1155 if (!ensureRenderTarget())
1156 {
1157 return NULL;
1158 }
1159
Jamie Madillac7579c2014-09-17 16:59:33 -04001160 updateStorageFaceLevel(index.layerIndex, index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001161 return mTexStorage->getRenderTarget(index);
Brandon Jones0511e802014-07-14 16:27:26 -07001162}
1163
Brandon Jones0511e802014-07-14 16:27:26 -07001164void TextureD3D_Cube::initializeStorage(bool renderTarget)
1165{
1166 // Only initialize the first time this texture is used as a render target or shader resource
1167 if (mTexStorage)
1168 {
1169 return;
1170 }
1171
1172 // do not attempt to create storage for nonexistant data
1173 if (!isFaceLevelComplete(0, 0))
1174 {
1175 return;
1176 }
1177
1178 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1179
1180 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1181 ASSERT(mTexStorage);
1182
1183 // flush image data to the storage
1184 updateStorage();
1185}
1186
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001187TextureStorage *TextureD3D_Cube::createCompleteStorage(bool renderTarget) const
Brandon Jones0511e802014-07-14 16:27:26 -07001188{
1189 GLsizei size = getBaseLevelWidth();
1190
1191 ASSERT(size > 0);
1192
1193 // use existing storage level count, when previously specified by TexStorage*D
1194 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1195
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001196 return mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
Brandon Jones0511e802014-07-14 16:27:26 -07001197}
1198
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001199void TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001200{
1201 SafeDelete(mTexStorage);
1202 mTexStorage = newCompleteTexStorage;
1203
1204 if (mTexStorage && mTexStorage->isManaged())
1205 {
1206 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1207 {
1208 for (int level = 0; level < mTexStorage->getLevelCount(); level++)
1209 {
Jamie Madill856d9d42014-09-18 15:08:49 -04001210 mImageArray[faceIndex][level]->setManagedSurfaceCube(mTexStorage, faceIndex, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001211 }
1212 }
1213 }
1214
1215 mDirtyImages = true;
1216}
1217
1218void TextureD3D_Cube::updateStorage()
1219{
1220 ASSERT(mTexStorage != NULL);
1221 GLint storageLevels = mTexStorage->getLevelCount();
1222 for (int face = 0; face < 6; face++)
1223 {
1224 for (int level = 0; level < storageLevels; level++)
1225 {
1226 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1227 {
1228 updateStorageFaceLevel(face, level);
1229 }
1230 }
1231 }
1232}
1233
Brandon Jones0511e802014-07-14 16:27:26 -07001234bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1235{
1236 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1237}
1238
Brandon Jones0511e802014-07-14 16:27:26 -07001239bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1240{
1241 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1242
1243 if (isImmutable())
1244 {
1245 return true;
1246 }
1247
1248 int baseSize = getBaseLevelWidth();
1249
1250 if (baseSize <= 0)
1251 {
1252 return false;
1253 }
1254
1255 // "isCubeComplete" checks for base level completeness and we must call that
1256 // to determine if any face at level 0 is complete. We omit that check here
1257 // to avoid re-checking cube-completeness for every face at level 0.
1258 if (level == 0)
1259 {
1260 return true;
1261 }
1262
1263 // Check that non-zero levels are consistent with the base level.
1264 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1265
1266 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1267 {
1268 return false;
1269 }
1270
1271 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1272 {
1273 return false;
1274 }
1275
1276 return true;
1277}
1278
1279void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
1280{
1281 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1282 ImageD3D *image = mImageArray[faceIndex][level];
1283
1284 if (image->isDirty())
1285 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001286 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1287 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1288 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
1289 commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001290 }
1291}
1292
1293void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1294{
1295 // If there currently is a corresponding storage texture image, it has these parameters
1296 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1297 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1298 const GLenum storageFormat = getBaseLevelInternalFormat();
1299
1300 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1301
1302 if (mTexStorage)
1303 {
1304 const int storageLevels = mTexStorage->getLevelCount();
1305
1306 if ((level >= storageLevels && storageLevels != 0) ||
1307 width != storageWidth ||
1308 height != storageHeight ||
1309 internalformat != storageFormat) // Discard mismatched storage
1310 {
1311 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1312 {
1313 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1314 {
1315 mImageArray[faceIndex][level]->markDirty();
1316 }
1317 }
1318
1319 SafeDelete(mTexStorage);
1320
1321 mDirtyImages = true;
1322 }
1323 }
1324}
1325
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001326gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001327{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001328 ASSERT(index.hasLayer());
1329
1330 GLint level = index.mipIndex;
1331 int faceIndex = static_cast<int>(index.layerIndex);
1332
Brandon Jones0511e802014-07-14 16:27:26 -07001333 if (isValidFaceLevel(faceIndex, level))
1334 {
1335 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001336 gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, region.x, region.y, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001337 if (error.isError())
1338 {
1339 return error;
1340 }
1341
1342 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001343 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001344
1345 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001346}
1347
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001348gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1349{
1350 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1351}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001352
Jamie Madillcb83dc12014-09-29 10:46:12 -04001353gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1354{
1355 // The "layer" of the image index corresponds to the cube face
1356 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1357}
1358
Brandon Jones78b1acd2014-07-15 15:33:07 -07001359TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001360 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001361{
1362 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1363 {
1364 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1365 }
1366}
1367
1368TextureD3D_3D::~TextureD3D_3D()
1369{
Austin Kinross69822602014-08-12 15:51:37 -07001370 // Delete the Images before the TextureStorage.
1371 // Images might be relying on the TextureStorage for some of their data.
1372 // 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 -07001373 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1374 {
1375 delete mImageArray[i];
1376 }
Austin Kinross69822602014-08-12 15:51:37 -07001377
1378 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001379}
1380
Brandon Jonescef06ff2014-08-05 13:27:48 -07001381Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001382{
1383 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001384 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001385 return mImageArray[level];
1386}
1387
Jamie Madillfeda4d22014-09-17 13:03:29 -04001388Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1389{
1390 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001391 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001392 ASSERT(index.type == GL_TEXTURE_3D);
1393 return mImageArray[index.mipIndex];
1394}
1395
Brandon Jonescef06ff2014-08-05 13:27:48 -07001396GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001397{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001398 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1399 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001400}
1401
Brandon Jones78b1acd2014-07-15 15:33:07 -07001402GLsizei TextureD3D_3D::getWidth(GLint level) const
1403{
1404 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1405 return mImageArray[level]->getWidth();
1406 else
1407 return 0;
1408}
1409
1410GLsizei TextureD3D_3D::getHeight(GLint level) const
1411{
1412 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1413 return mImageArray[level]->getHeight();
1414 else
1415 return 0;
1416}
1417
1418GLsizei TextureD3D_3D::getDepth(GLint level) const
1419{
1420 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1421 return mImageArray[level]->getDepth();
1422 else
1423 return 0;
1424}
1425
1426GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1427{
1428 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1429 return mImageArray[level]->getInternalFormat();
1430 else
1431 return GL_NONE;
1432}
1433
1434bool TextureD3D_3D::isDepth(GLint level) const
1435{
Geoff Lang5d601382014-07-22 15:14:06 -04001436 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001437}
1438
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001439gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1440 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1441 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001442{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001443 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001444 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1445
Brandon Jones78b1acd2014-07-15 15:33:07 -07001446 redefineImage(level, sizedInternalFormat, width, height, depth);
1447
1448 bool fastUnpacked = false;
1449
1450 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1451 if (isFastUnpackable(unpack, sizedInternalFormat))
1452 {
1453 // Will try to create RT storage if it does not exist
Jamie Madillac7579c2014-09-17 16:59:33 -04001454 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1455 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001456 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1457
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001458 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001459 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001460 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1461 if (error.isError())
1462 {
1463 return error;
1464 }
1465
Brandon Jones78b1acd2014-07-15 15:33:07 -07001466 // Ensure we don't overwrite our newly initialized data
1467 mImageArray[level]->markClean();
1468
1469 fastUnpacked = true;
1470 }
1471 }
1472
1473 if (!fastUnpacked)
1474 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001475 gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
1476 if (error.isError())
1477 {
1478 return error;
1479 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001480 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001481
1482 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001483}
1484
Geoff Langb5348332014-09-02 13:16:34 -04001485gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1486 GLsizei width, GLsizei height,GLsizei depth,
1487 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001488{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001489 ASSERT(target == GL_TEXTURE_3D);
1490
Brandon Jones78b1acd2014-07-15 15:33:07 -07001491 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1492 redefineImage(level, format, width, height, depth);
1493
Geoff Langb5348332014-09-02 13:16:34 -04001494 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001495}
1496
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001497gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1498 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1499 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001500{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001501 ASSERT(target == GL_TEXTURE_3D);
1502
Brandon Jones78b1acd2014-07-15 15:33:07 -07001503 bool fastUnpacked = false;
1504
Jamie Madillac7579c2014-09-17 16:59:33 -04001505 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1506
Brandon Jones78b1acd2014-07-15 15:33:07 -07001507 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1508 if (isFastUnpackable(unpack, getInternalFormat(level)))
1509 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001510 RenderTarget *destRenderTarget = getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001511
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001512 if (destRenderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001513 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001514 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001515 gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1516 if (error.isError())
1517 {
1518 return error;
1519 }
1520
Brandon Jones78b1acd2014-07-15 15:33:07 -07001521 // Ensure we don't overwrite our newly initialized data
1522 mImageArray[level]->markClean();
1523
1524 fastUnpacked = true;
1525 }
1526 }
1527
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001528 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001529 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001530 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1531 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001532 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001533
1534 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001535}
1536
Geoff Langb5348332014-09-02 13:16:34 -04001537gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1538 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1539 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001540{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001541 ASSERT(target == GL_TEXTURE_3D);
1542
Geoff Langb5348332014-09-02 13:16:34 -04001543 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1544 format, imageSize, pixels, mImageArray[level]);
1545 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001546 {
Geoff Langb5348332014-09-02 13:16:34 -04001547 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001548 }
Geoff Langb5348332014-09-02 13:16:34 -04001549
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001550 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1551 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1552 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001553}
1554
Brandon Jonescef06ff2014-08-05 13:27:48 -07001555void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1556{
1557 UNIMPLEMENTED();
1558}
1559
Brandon Jones78b1acd2014-07-15 15:33:07 -07001560void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
1561{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001562 ASSERT(target == GL_TEXTURE_3D);
1563
Brandon Jones78b1acd2014-07-15 15:33:07 -07001564 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
1565 // the current level we're copying to is defined (with appropriate format, width & height)
1566 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
1567
1568 if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
1569 {
1570 mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
1571 mDirtyImages = true;
1572 }
1573 else
1574 {
1575 ensureRenderTarget();
1576
1577 if (isValidLevel(level))
1578 {
1579 updateStorageLevel(level);
1580
1581 gl::Rectangle sourceRect;
1582 sourceRect.x = x;
1583 sourceRect.width = width;
1584 sourceRect.y = y;
1585 sourceRect.height = height;
1586
Jamie Madill856d9d42014-09-18 15:08:49 -04001587 mRenderer->copyImage3D(source, sourceRect,
1588 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1589 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001590 }
1591 }
1592}
1593
Brandon Jonescef06ff2014-08-05 13:27:48 -07001594void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001595{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001596 ASSERT(target == GL_TEXTURE_3D);
1597
Brandon Jones78b1acd2014-07-15 15:33:07 -07001598 for (int level = 0; level < levels; level++)
1599 {
1600 GLsizei levelWidth = std::max(1, width >> level);
1601 GLsizei levelHeight = std::max(1, height >> level);
1602 GLsizei levelDepth = std::max(1, depth >> level);
1603 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1604 }
1605
1606 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1607 {
1608 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1609 }
1610
1611 mImmutable = true;
1612
Jamie Madillc4833262014-09-18 16:18:26 -04001613 bool renderTarget = IsRenderTargetUsage(mUsage);
1614 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001615 setCompleteTexStorage(storage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616}
1617
Brandon Jones6053a522014-07-25 16:22:09 -07001618void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001619{
Brandon Jones6053a522014-07-25 16:22:09 -07001620 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001621}
1622
Brandon Jones6053a522014-07-25 16:22:09 -07001623void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001624{
Brandon Jones6053a522014-07-25 16:22:09 -07001625 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001626}
1627
Brandon Jones6053a522014-07-25 16:22:09 -07001628
Jamie Madill4aa79e12014-09-29 10:46:14 -04001629void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001630{
1631 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1632 int levelCount = mipLevels();
1633 for (int level = 1; level < levelCount; level++)
1634 {
1635 redefineImage(level, getBaseLevelInternalFormat(),
1636 std::max(getBaseLevelWidth() >> level, 1),
1637 std::max(getBaseLevelHeight() >> level, 1),
1638 std::max(getBaseLevelDepth() >> level, 1));
1639 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001640}
1641
Jamie Madillac7579c2014-09-17 16:59:33 -04001642unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001643{
Jamie Madillc4833262014-09-18 16:18:26 -04001644 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001645}
1646
Jamie Madillac7579c2014-09-17 16:59:33 -04001647RenderTarget *TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001648{
1649 // ensure the underlying texture is created
1650 if (!ensureRenderTarget())
1651 {
1652 return NULL;
1653 }
1654
Jamie Madillac7579c2014-09-17 16:59:33 -04001655 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656 {
Jamie Madillac7579c2014-09-17 16:59:33 -04001657 updateStorage();
1658 }
1659 else
1660 {
1661 updateStorageLevel(index.mipIndex);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001662 }
1663
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001664 return mTexStorage->getRenderTarget(index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001665}
1666
1667void TextureD3D_3D::initializeStorage(bool renderTarget)
1668{
1669 // Only initialize the first time this texture is used as a render target or shader resource
1670 if (mTexStorage)
1671 {
1672 return;
1673 }
1674
1675 // do not attempt to create storage for nonexistant data
1676 if (!isLevelComplete(0))
1677 {
1678 return;
1679 }
1680
1681 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1682
1683 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
1684 ASSERT(mTexStorage);
1685
1686 // flush image data to the storage
1687 updateStorage();
1688}
1689
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001690TextureStorage *TextureD3D_3D::createCompleteStorage(bool renderTarget) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001691{
1692 GLsizei width = getBaseLevelWidth();
1693 GLsizei height = getBaseLevelHeight();
1694 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04001695 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001696
1697 ASSERT(width > 0 && height > 0 && depth > 0);
1698
1699 // use existing storage level count, when previously specified by TexStorage*D
1700 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
1701
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001702 return mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001703}
1704
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001705void TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001706{
1707 SafeDelete(mTexStorage);
1708 mTexStorage = newCompleteTexStorage;
1709 mDirtyImages = true;
1710
1711 // We do not support managed 3D storage, as that is D3D9/ES2-only
1712 ASSERT(!mTexStorage->isManaged());
1713}
1714
1715void TextureD3D_3D::updateStorage()
1716{
1717 ASSERT(mTexStorage != NULL);
1718 GLint storageLevels = mTexStorage->getLevelCount();
1719 for (int level = 0; level < storageLevels; level++)
1720 {
1721 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1722 {
1723 updateStorageLevel(level);
1724 }
1725 }
1726}
1727
Brandon Jones78b1acd2014-07-15 15:33:07 -07001728bool TextureD3D_3D::isValidLevel(int level) const
1729{
1730 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1731}
1732
1733bool TextureD3D_3D::isLevelComplete(int level) const
1734{
1735 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1736
1737 if (isImmutable())
1738 {
1739 return true;
1740 }
1741
1742 GLsizei width = getBaseLevelWidth();
1743 GLsizei height = getBaseLevelHeight();
1744 GLsizei depth = getBaseLevelDepth();
1745
1746 if (width <= 0 || height <= 0 || depth <= 0)
1747 {
1748 return false;
1749 }
1750
1751 if (level == 0)
1752 {
1753 return true;
1754 }
1755
1756 ImageD3D *levelImage = mImageArray[level];
1757
1758 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
1759 {
1760 return false;
1761 }
1762
1763 if (levelImage->getWidth() != std::max(1, width >> level))
1764 {
1765 return false;
1766 }
1767
1768 if (levelImage->getHeight() != std::max(1, height >> level))
1769 {
1770 return false;
1771 }
1772
1773 if (levelImage->getDepth() != std::max(1, depth >> level))
1774 {
1775 return false;
1776 }
1777
1778 return true;
1779}
1780
1781void TextureD3D_3D::updateStorageLevel(int level)
1782{
1783 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1784 ASSERT(isLevelComplete(level));
1785
1786 if (mImageArray[level]->isDirty())
1787 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001788 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1789 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1790 commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001791 }
1792}
1793
1794void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
1795{
1796 // If there currently is a corresponding storage texture image, it has these parameters
1797 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1798 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1799 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
1800 const GLenum storageFormat = getBaseLevelInternalFormat();
1801
1802 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
1803
1804 if (mTexStorage)
1805 {
1806 const int storageLevels = mTexStorage->getLevelCount();
1807
1808 if ((level >= storageLevels && storageLevels != 0) ||
1809 width != storageWidth ||
1810 height != storageHeight ||
1811 depth != storageDepth ||
1812 internalformat != storageFormat) // Discard mismatched storage
1813 {
1814 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1815 {
1816 mImageArray[i]->markDirty();
1817 }
1818
1819 SafeDelete(mTexStorage);
1820 mDirtyImages = true;
1821 }
1822 }
1823}
1824
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001825gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001826{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001827 ASSERT(!index.hasLayer());
1828 GLint level = index.mipIndex;
1829
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830 if (isValidLevel(level))
1831 {
1832 ImageD3D *image = mImageArray[level];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001833 gl::Error error = image->copyToStorage3D(mTexStorage, level, region.x, region.y, region.z, region.width, region.height, region.depth);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001834 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001835 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001836 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001837 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001838
1839 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001840 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001841
1842 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001843}
1844
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001845gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
1846{
1847 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
1848 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
1849}
Brandon Jones142ec422014-07-16 10:31:30 -07001850
Jamie Madillcb83dc12014-09-29 10:46:12 -04001851gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
1852{
1853 // The "layer" here does not apply to 3D images. We use one Image per mip.
1854 return gl::ImageIndex::Make3D(mip);
1855}
1856
Brandon Jones142ec422014-07-16 10:31:30 -07001857TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001858 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07001859{
1860 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
1861 {
1862 mLayerCounts[level] = 0;
1863 mImageArray[level] = NULL;
1864 }
1865}
1866
1867TextureD3D_2DArray::~TextureD3D_2DArray()
1868{
Austin Kinross69822602014-08-12 15:51:37 -07001869 // Delete the Images before the TextureStorage.
1870 // Images might be relying on the TextureStorage for some of their data.
1871 // 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 -07001872 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07001873 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07001874}
1875
Brandon Jones142ec422014-07-16 10:31:30 -07001876Image *TextureD3D_2DArray::getImage(int level, int layer) const
1877{
1878 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1879 ASSERT(layer < mLayerCounts[level]);
1880 return mImageArray[level][layer];
1881}
1882
Jamie Madillfeda4d22014-09-17 13:03:29 -04001883Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
1884{
1885 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1886 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
1887 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
1888 return mImageArray[index.mipIndex][index.layerIndex];
1889}
1890
Brandon Jones142ec422014-07-16 10:31:30 -07001891GLsizei TextureD3D_2DArray::getLayerCount(int level) const
1892{
1893 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1894 return mLayerCounts[level];
1895}
1896
Brandon Jones142ec422014-07-16 10:31:30 -07001897GLsizei TextureD3D_2DArray::getWidth(GLint level) const
1898{
1899 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
1900}
1901
1902GLsizei TextureD3D_2DArray::getHeight(GLint level) const
1903{
1904 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
1905}
1906
Brandon Jones142ec422014-07-16 10:31:30 -07001907GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
1908{
1909 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
1910}
1911
1912bool TextureD3D_2DArray::isDepth(GLint level) const
1913{
Geoff Lang5d601382014-07-22 15:14:06 -04001914 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07001915}
1916
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001917gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1918 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1919 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001920{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001921 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1922
Geoff Lang5d601382014-07-22 15:14:06 -04001923 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1924
Brandon Jones142ec422014-07-16 10:31:30 -07001925 redefineImage(level, sizedInternalFormat, width, height, depth);
1926
Geoff Lang5d601382014-07-22 15:14:06 -04001927 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
1928 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001929
1930 for (int i = 0; i < depth; i++)
1931 {
1932 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001933 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
1934 if (error.isError())
1935 {
1936 return error;
1937 }
Brandon Jones142ec422014-07-16 10:31:30 -07001938 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001939
1940 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001941}
1942
Geoff Langb5348332014-09-02 13:16:34 -04001943gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
1944 GLsizei width, GLsizei height, GLsizei depth,
1945 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001946{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001947 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1948
Brandon Jones142ec422014-07-16 10:31:30 -07001949 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1950 redefineImage(level, format, width, height, depth);
1951
Geoff Lang5d601382014-07-22 15:14:06 -04001952 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
1953 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07001954
1955 for (int i = 0; i < depth; i++)
1956 {
1957 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04001958 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
1959 if (error.isError())
1960 {
1961 return error;
1962 }
Brandon Jones142ec422014-07-16 10:31:30 -07001963 }
Geoff Langb5348332014-09-02 13:16:34 -04001964
1965 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001966}
1967
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001968gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1969 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1970 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001971{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001972 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1973
Geoff Lang5d601382014-07-22 15:14:06 -04001974 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
1975 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07001976
1977 for (int i = 0; i < depth; i++)
1978 {
1979 int layer = zoffset + i;
1980 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
1981
Jamie Madillfeda4d22014-09-17 13:03:29 -04001982 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04001983 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
1984 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001985 if (error.isError())
1986 {
1987 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07001988 }
1989 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001990
1991 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07001992}
1993
Geoff Langb5348332014-09-02 13:16:34 -04001994gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1995 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1996 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07001997{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001998 ASSERT(target == GL_TEXTURE_2D_ARRAY);
1999
Geoff Lang5d601382014-07-22 15:14:06 -04002000 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2001 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002002
2003 for (int i = 0; i < depth; i++)
2004 {
2005 int layer = zoffset + i;
2006 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2007
Geoff Langb5348332014-09-02 13:16:34 -04002008 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2009 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002010 {
Geoff Langb5348332014-09-02 13:16:34 -04002011 return error;
2012 }
2013
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002014 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2015 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2016 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002017 if (error.isError())
2018 {
2019 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002020 }
2021 }
Geoff Langb5348332014-09-02 13:16:34 -04002022
2023 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002024}
2025
Brandon Jonescef06ff2014-08-05 13:27:48 -07002026void TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2027{
2028 UNIMPLEMENTED();
2029}
2030
Brandon Jones142ec422014-07-16 10:31:30 -07002031void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
2032{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002033 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2034
Brandon Jones142ec422014-07-16 10:31:30 -07002035 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
2036 // the current level we're copying to is defined (with appropriate format, width & height)
2037 bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
2038
2039 if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
2040 {
2041 mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
2042 mDirtyImages = true;
2043 }
2044 else
2045 {
2046 ensureRenderTarget();
2047
2048 if (isValidLevel(level))
2049 {
2050 updateStorageLevel(level);
2051
2052 gl::Rectangle sourceRect;
2053 sourceRect.x = x;
2054 sourceRect.width = width;
2055 sourceRect.y = y;
2056 sourceRect.height = height;
2057
Jamie Madill856d9d42014-09-18 15:08:49 -04002058 mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2059 xoffset, yoffset, zoffset, mTexStorage, level);
Brandon Jones142ec422014-07-16 10:31:30 -07002060 }
2061 }
2062}
2063
Brandon Jonescef06ff2014-08-05 13:27:48 -07002064void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002065{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002066 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2067
Brandon Jones142ec422014-07-16 10:31:30 -07002068 deleteImages();
2069
2070 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2071 {
2072 GLsizei levelWidth = std::max(1, width >> level);
2073 GLsizei levelHeight = std::max(1, height >> level);
2074
2075 mLayerCounts[level] = (level < levels ? depth : 0);
2076
2077 if (mLayerCounts[level] > 0)
2078 {
2079 // Create new images for this level
2080 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2081
2082 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2083 {
2084 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2085 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2086 levelHeight, 1, true);
2087 }
2088 }
2089 }
2090
2091 mImmutable = true;
Jamie Madillc4833262014-09-18 16:18:26 -04002092
2093 bool renderTarget = IsRenderTargetUsage(mUsage);
2094 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002095 setCompleteTexStorage(storage);
Brandon Jones142ec422014-07-16 10:31:30 -07002096}
2097
Brandon Jones6053a522014-07-25 16:22:09 -07002098void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002099{
Brandon Jones6053a522014-07-25 16:22:09 -07002100 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002101}
2102
Brandon Jones6053a522014-07-25 16:22:09 -07002103void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002104{
Brandon Jones6053a522014-07-25 16:22:09 -07002105 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002106}
2107
Brandon Jones6053a522014-07-25 16:22:09 -07002108
Jamie Madill4aa79e12014-09-29 10:46:14 -04002109void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002110{
2111 int baseWidth = getBaseLevelWidth();
2112 int baseHeight = getBaseLevelHeight();
2113 int baseDepth = getBaseLevelDepth();
2114 GLenum baseFormat = getBaseLevelInternalFormat();
2115
2116 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2117 int levelCount = mipLevels();
2118 for (int level = 1; level < levelCount; level++)
2119 {
2120 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2121 }
Brandon Jones142ec422014-07-16 10:31:30 -07002122}
2123
Jamie Madillac7579c2014-09-17 16:59:33 -04002124unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002125{
Jamie Madillc4833262014-09-18 16:18:26 -04002126 return (ensureRenderTarget() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002127}
2128
Jamie Madillac7579c2014-09-17 16:59:33 -04002129RenderTarget *TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002130{
2131 // ensure the underlying texture is created
2132 if (!ensureRenderTarget())
2133 {
2134 return NULL;
2135 }
2136
Jamie Madillac7579c2014-09-17 16:59:33 -04002137 updateStorageLevel(index.mipIndex);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002138 return mTexStorage->getRenderTarget(index);
Brandon Jones142ec422014-07-16 10:31:30 -07002139}
2140
2141void TextureD3D_2DArray::initializeStorage(bool renderTarget)
2142{
2143 // Only initialize the first time this texture is used as a render target or shader resource
2144 if (mTexStorage)
2145 {
2146 return;
2147 }
2148
2149 // do not attempt to create storage for nonexistant data
2150 if (!isLevelComplete(0))
2151 {
2152 return;
2153 }
2154
2155 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2156
2157 setCompleteTexStorage(createCompleteStorage(createRenderTarget));
2158 ASSERT(mTexStorage);
2159
2160 // flush image data to the storage
2161 updateStorage();
2162}
2163
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002164TextureStorage *TextureD3D_2DArray::createCompleteStorage(bool renderTarget) const
Brandon Jones142ec422014-07-16 10:31:30 -07002165{
2166 GLsizei width = getBaseLevelWidth();
2167 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002168 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002169 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002170
2171 ASSERT(width > 0 && height > 0 && depth > 0);
2172
2173 // use existing storage level count, when previously specified by TexStorage*D
2174 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2175
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002176 return mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
Brandon Jones142ec422014-07-16 10:31:30 -07002177}
2178
Jamie Madill2f06dbf2014-09-18 15:08:50 -04002179void TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002180{
2181 SafeDelete(mTexStorage);
2182 mTexStorage = newCompleteTexStorage;
2183 mDirtyImages = true;
2184
2185 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2186 ASSERT(!mTexStorage->isManaged());
2187}
2188
2189void TextureD3D_2DArray::updateStorage()
2190{
2191 ASSERT(mTexStorage != NULL);
2192 GLint storageLevels = mTexStorage->getLevelCount();
2193 for (int level = 0; level < storageLevels; level++)
2194 {
2195 if (isLevelComplete(level))
2196 {
2197 updateStorageLevel(level);
2198 }
2199 }
2200}
2201
Brandon Jones142ec422014-07-16 10:31:30 -07002202bool TextureD3D_2DArray::isValidLevel(int level) const
2203{
2204 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2205}
2206
2207bool TextureD3D_2DArray::isLevelComplete(int level) const
2208{
2209 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2210
2211 if (isImmutable())
2212 {
2213 return true;
2214 }
2215
2216 GLsizei width = getBaseLevelWidth();
2217 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002218 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002219
2220 if (width <= 0 || height <= 0 || layers <= 0)
2221 {
2222 return false;
2223 }
2224
2225 if (level == 0)
2226 {
2227 return true;
2228 }
2229
2230 if (getInternalFormat(level) != getInternalFormat(0))
2231 {
2232 return false;
2233 }
2234
2235 if (getWidth(level) != std::max(1, width >> level))
2236 {
2237 return false;
2238 }
2239
2240 if (getHeight(level) != std::max(1, height >> level))
2241 {
2242 return false;
2243 }
2244
Jamie Madill3269bcb2014-09-30 16:33:52 -04002245 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002246 {
2247 return false;
2248 }
2249
2250 return true;
2251}
2252
2253void TextureD3D_2DArray::updateStorageLevel(int level)
2254{
2255 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2256 ASSERT(isLevelComplete(level));
2257
2258 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2259 {
2260 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2261 if (mImageArray[level][layer]->isDirty())
2262 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002263 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2264 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
2265 commitRegion(index, region);
Brandon Jones142ec422014-07-16 10:31:30 -07002266 }
2267 }
2268}
2269
2270void TextureD3D_2DArray::deleteImages()
2271{
2272 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2273 {
2274 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2275 {
2276 delete mImageArray[level][layer];
2277 }
2278 delete[] mImageArray[level];
2279 mImageArray[level] = NULL;
2280 mLayerCounts[level] = 0;
2281 }
2282}
2283
2284void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2285{
2286 // If there currently is a corresponding storage texture image, it has these parameters
2287 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2288 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002289 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002290 const GLenum storageFormat = getBaseLevelInternalFormat();
2291
2292 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2293 {
2294 delete mImageArray[level][layer];
2295 }
2296 delete[] mImageArray[level];
2297 mImageArray[level] = NULL;
2298 mLayerCounts[level] = depth;
2299
2300 if (depth > 0)
2301 {
2302 mImageArray[level] = new ImageD3D*[depth]();
2303
2304 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2305 {
2306 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2307 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2308 }
2309 }
2310
2311 if (mTexStorage)
2312 {
2313 const int storageLevels = mTexStorage->getLevelCount();
2314
2315 if ((level >= storageLevels && storageLevels != 0) ||
2316 width != storageWidth ||
2317 height != storageHeight ||
2318 depth != storageDepth ||
2319 internalformat != storageFormat) // Discard mismatched storage
2320 {
2321 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2322 {
2323 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2324 {
2325 mImageArray[level][layer]->markDirty();
2326 }
2327 }
2328
2329 delete mTexStorage;
2330 mTexStorage = NULL;
2331 mDirtyImages = true;
2332 }
2333 }
2334}
2335
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002336gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002337{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002338 ASSERT(index.hasLayer());
2339 GLint level = index.mipIndex;
2340 GLint layerTarget = index.layerIndex;
2341
Jamie Madill3269bcb2014-09-30 16:33:52 -04002342 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002343 {
2344 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002345 gl::Error error = image->copyToStorage2DArray(mTexStorage, level, region.x, region.y, layerTarget, region.width, region.height);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002346 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002347 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002348 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002349 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002350
2351 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002352 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002353
2354 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002355}
2356
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002357gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2358{
2359 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2360}
2361
Jamie Madillcb83dc12014-09-29 10:46:12 -04002362gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2363{
2364 return gl::ImageIndex::Make2DArray(mip, layer);
2365}
2366
Brandon Jones78b1acd2014-07-15 15:33:07 -07002367}