blob: 9adfc379251420be96f58a3bc3f49818032dbd40 [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
Jamie Madillec6de4e2014-10-20 10:59:56 -040093bool TextureD3D::shouldUseSetData(const Image *image) const
94{
95 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
96 {
97 return false;
98 }
99
100 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
101
102 // We can only handle full updates for depth-stencil textures, so to avoid complications
103 // disable them entirely.
104 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
105 {
106 return false;
107 }
108
109 // TODO(jmadill): Handle compressed internal formats
110 return (mTexStorage && !internalFormat.compressed);
111}
112
Jamie Madillba6bc952014-10-06 10:56:22 -0400113gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700114{
Jamie Madillba6bc952014-10-06 10:56:22 -0400115 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400116 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400117
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700118 // No-op
119 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
120 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400121 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700122 }
123
124 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
125 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
Jamie Madill9aca0592014-10-06 16:26:59 -0400126 const uint8_t *pixelData = NULL;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700127
128 if (unpack.pixelBuffer.id() != 0)
129 {
130 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
131 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
132 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
133 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
134 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
135 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400136 pixelData = static_cast<const uint8_t *>(bufferData) + offset;
137 }
138 else
139 {
140 pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700141 }
142
143 if (pixelData != NULL)
144 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400145 gl::Error error(GL_NO_ERROR);
146
Jamie Madillec6de4e2014-10-20 10:59:56 -0400147 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400148 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400149 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400150 }
151 else
152 {
153 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
154 }
155
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400156 if (error.isError())
157 {
158 return error;
159 }
160
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700161 mDirtyImages = true;
162 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400163
164 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165}
166
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400167gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
168 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700169{
Jamie Madill9aca0592014-10-06 16:26:59 -0400170 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700171
172 // CPU readback & copy where direct GPU copy is not supported
173 if (unpack.pixelBuffer.id() != 0)
174 {
175 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200176 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700177 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
178 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
179 const void *bufferData = pixelBuffer->getImplementation()->getData();
Jamie Madill9aca0592014-10-06 16:26:59 -0400180 pixelData = static_cast<const uint8_t *>(bufferData)+offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700181 }
182
183 if (pixelData != NULL)
184 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400185 Image *image = getImage(index);
186 ASSERT(image);
187
Jamie Madill9aca0592014-10-06 16:26:59 -0400188 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400189 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400190 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400191 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400192 }
193
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400194 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
195 type, pixelData);
196 if (error.isError())
197 {
198 return error;
199 }
200
Jamie Madille6b6da02014-10-02 11:03:14 -0400201 error = commitRegion(index, region);
202 if (error.isError())
203 {
204 return error;
205 }
206
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700207 mDirtyImages = true;
208 }
209
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400210 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700211}
212
Geoff Langb5348332014-09-02 13:16:34 -0400213gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700214{
215 if (pixels != NULL)
216 {
Geoff Langb5348332014-09-02 13:16:34 -0400217 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
218 if (error.isError())
219 {
220 return error;
221 }
222
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700223 mDirtyImages = true;
224 }
Geoff Langb5348332014-09-02 13:16:34 -0400225
226 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227}
228
Geoff Langb5348332014-09-02 13:16:34 -0400229gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700230 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231{
232 if (pixels != NULL)
233 {
Geoff Langb5348332014-09-02 13:16:34 -0400234 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
235 if (error.isError())
236 {
237 return error;
238 }
239
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240 mDirtyImages = true;
241 }
242
Geoff Langb5348332014-09-02 13:16:34 -0400243 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700244}
245
246bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
247{
248 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
249}
250
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400251gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
252 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700253{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400254 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700255 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
256 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400257 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258 }
259
260 // In order to perform the fast copy through the shader, we must have the right format, and be able
261 // to create a render target.
262 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
263
Jacek Cabana5521de2014-10-01 17:23:46 +0200264 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700265
Geoff Langae5122c2014-08-27 14:08:43 -0400266 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
267 if (error.isError())
268 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400269 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400270 }
271
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400272 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700273}
274
275GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
276{
277 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
278 {
279 // Maximum number of levels
280 return gl::log2(std::max(std::max(width, height), depth)) + 1;
281 }
282 else
283 {
284 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
285 return 1;
286 }
287}
288
289int TextureD3D::mipLevels() const
290{
291 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
292}
293
Jamie Madill98553e32014-09-30 16:33:50 -0400294TextureStorage *TextureD3D::getStorage()
295{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400296 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400297 return mTexStorage;
298}
299
Jamie Madill3269bcb2014-09-30 16:33:52 -0400300Image *TextureD3D::getBaseLevelImage() const
301{
302 return getImage(getImageIndex(0, 0));
303}
304
Jamie Madill4aa79e12014-09-29 10:46:14 -0400305void TextureD3D::generateMipmaps()
306{
Jamie Madill9aca0592014-10-06 16:26:59 -0400307 GLint mipCount = mipLevels();
308
309 if (mipCount == 1)
310 {
311 return; // no-op
312 }
313
314 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400315 initMipmapsImages();
316
317 // We know that all layers have the same dimension, for the texture to be complete
318 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400319
Jamie Madill9aca0592014-10-06 16:26:59 -0400320 // When making mipmaps with the setData workaround enabled, the texture storage has
321 // the image data already. For non-render-target storage, we have to pull it out into
322 // an image layer.
323 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
324 {
325 if (!mTexStorage->isRenderTarget())
326 {
327 // Copy from the storage mip 0 to Image mip 0
328 for (GLint layer = 0; layer < layerCount; ++layer)
329 {
330 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400331
Jamie Madill9aca0592014-10-06 16:26:59 -0400332 Image *image = getImage(srcIndex);
333 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
334 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
335 }
336 }
337 else
338 {
339 updateStorage();
340 }
341 }
342
343 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400344
345 for (GLint layer = 0; layer < layerCount; ++layer)
346 {
347 for (GLint mip = 1; mip < mipCount; ++mip)
348 {
349 ASSERT(getLayerCount(mip) == layerCount);
350
351 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
352 gl::ImageIndex destIndex = getImageIndex(mip, layer);
353
354 if (renderableStorage)
355 {
356 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400357 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400358 }
359 else
360 {
361 // CPU-side mipmapping
362 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
363 }
364 }
365 }
366}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700367
Jamie Madill135570a2014-09-30 16:33:51 -0400368bool TextureD3D::isBaseImageZeroSize() const
369{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400370 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400371
372 if (!baseImage || baseImage->getWidth() <= 0)
373 {
374 return true;
375 }
376
377 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
378 {
379 return true;
380 }
381
382 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
383 {
384 return true;
385 }
386
387 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
388 {
389 return true;
390 }
391
392 return false;
393}
394
Geoff Langef7b0162014-09-04 13:29:23 -0400395gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400396{
Geoff Langef7b0162014-09-04 13:29:23 -0400397 gl::Error error = initializeStorage(true);
398 if (error.isError())
399 {
400 return error;
401 }
Jamie Madill135570a2014-09-30 16:33:51 -0400402
403 if (!isBaseImageZeroSize())
404 {
405 ASSERT(mTexStorage);
406 if (!mTexStorage->isRenderTarget())
407 {
Geoff Langef7b0162014-09-04 13:29:23 -0400408 TextureStorage *newRenderTargetStorage = NULL;
409 error = createCompleteStorage(true, &newRenderTargetStorage);
410 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400411 {
Geoff Langef7b0162014-09-04 13:29:23 -0400412 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400413 }
414
Geoff Langef7b0162014-09-04 13:29:23 -0400415 error = mTexStorage->copyToStorage(newRenderTargetStorage);
416 if (error.isError())
417 {
418 SafeDelete(newRenderTargetStorage);
419 return error;
420 }
421
422 error = setCompleteTexStorage(newRenderTargetStorage);
423 if (error.isError())
424 {
425 SafeDelete(newRenderTargetStorage);
426 return error;
427 }
Jamie Madill135570a2014-09-30 16:33:51 -0400428 }
429 }
430
Geoff Langef7b0162014-09-04 13:29:23 -0400431 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400432}
433
Jamie Madille76bdda2014-10-20 17:13:52 -0400434bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
435{
436 rx::Image *image = getImage(index);
437 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
438 return (image->isRenderableFormat() && levelsComplete);
439}
440
Brandon Jones78b1acd2014-07-15 15:33:07 -0700441TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400442 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700443{
444 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
445 {
446 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
447 }
448}
449
450TextureD3D_2D::~TextureD3D_2D()
451{
Austin Kinross69822602014-08-12 15:51:37 -0700452 // Delete the Images before the TextureStorage.
453 // Images might be relying on the TextureStorage for some of their data.
454 // 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 -0700455 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
456 {
457 delete mImageArray[i];
458 }
Austin Kinross69822602014-08-12 15:51:37 -0700459
460 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700461}
462
Brandon Jonescef06ff2014-08-05 13:27:48 -0700463Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700464{
465 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700466 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700467 return mImageArray[level];
468}
469
Jamie Madillfeda4d22014-09-17 13:03:29 -0400470Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
471{
472 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400473 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400474 ASSERT(index.type == GL_TEXTURE_2D);
475 return mImageArray[index.mipIndex];
476}
477
Brandon Jonescef06ff2014-08-05 13:27:48 -0700478GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700479{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700480 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
481 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700482}
483
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700484GLsizei TextureD3D_2D::getWidth(GLint level) const
485{
486 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
487 return mImageArray[level]->getWidth();
488 else
489 return 0;
490}
491
492GLsizei TextureD3D_2D::getHeight(GLint level) const
493{
494 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
495 return mImageArray[level]->getHeight();
496 else
497 return 0;
498}
499
500GLenum TextureD3D_2D::getInternalFormat(GLint level) const
501{
502 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
503 return mImageArray[level]->getInternalFormat();
504 else
505 return GL_NONE;
506}
507
508GLenum TextureD3D_2D::getActualFormat(GLint level) const
509{
510 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
511 return mImageArray[level]->getActualFormat();
512 else
513 return GL_NONE;
514}
515
516bool TextureD3D_2D::isDepth(GLint level) const
517{
Geoff Lang5d601382014-07-22 15:14:06 -0400518 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700519}
520
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400521gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
522 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
523 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700524{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700525 ASSERT(target == GL_TEXTURE_2D && depth == 1);
526
Geoff Lang5d601382014-07-22 15:14:06 -0400527 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
528
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700529 bool fastUnpacked = false;
530
Brandon Jonescef06ff2014-08-05 13:27:48 -0700531 redefineImage(level, sizedInternalFormat, width, height);
532
Jamie Madillba6bc952014-10-06 10:56:22 -0400533 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
534
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700535 // Attempt a fast gpu copy of the pixel data to the surface
536 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
537 {
538 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400539 RenderTarget *destRenderTarget = NULL;
540 gl::Error error = getRenderTarget(index, &destRenderTarget);
541 if (error.isError())
542 {
543 return error;
544 }
545
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700546 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
547
Geoff Lang64f23f62014-09-10 14:40:12 -0400548 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
549 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700550 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400551 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400553
554 // Ensure we don't overwrite our newly initialized data
555 mImageArray[level]->markClean();
556
557 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558 }
559
560 if (!fastUnpacked)
561 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400562 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400563 if (error.isError())
564 {
565 return error;
566 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700567 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400568
569 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700570}
571
Geoff Langb5348332014-09-02 13:16:34 -0400572gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
573 GLsizei width, GLsizei height, GLsizei depth,
574 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700576 ASSERT(target == GL_TEXTURE_2D && depth == 1);
577
578 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
579 redefineImage(level, format, width, height);
580
Geoff Langb5348332014-09-02 13:16:34 -0400581 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700582}
583
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400584gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
585 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
586 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700588 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
589
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700590 bool fastUnpacked = false;
591
Jamie Madillac7579c2014-09-17 16:59:33 -0400592 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400593 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700594 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
595 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400596 RenderTarget *renderTarget = NULL;
597 gl::Error error = getRenderTarget(index, &renderTarget);
598 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400600 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700601 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400602
603 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
604 if (error.isError())
605 {
606 return error;
607 }
608
609 // Ensure we don't overwrite our newly initialized data
610 mImageArray[level]->markClean();
611
612 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700613 }
614
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400615 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400617 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
618 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400620
621 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622}
623
Geoff Langb5348332014-09-02 13:16:34 -0400624gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
625 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
626 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700627{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700628 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
629
Geoff Langb5348332014-09-02 13:16:34 -0400630 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
631 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700632 {
Geoff Langb5348332014-09-02 13:16:34 -0400633 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700634 }
Geoff Langb5348332014-09-02 13:16:34 -0400635
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400636 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
637 gl::Box region(xoffset, yoffset, 0, width, height, 1);
638 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700639}
640
Geoff Langef7b0162014-09-04 13:29:23 -0400641gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
642 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700644 ASSERT(target == GL_TEXTURE_2D);
645
646 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
647 redefineImage(level, sizedInternalFormat, width, height);
648
Jamie Madill82bf0c52014-10-03 11:50:53 -0400649 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400650 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400651
Jamie Madille76bdda2014-10-20 17:13:52 -0400652 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700653 {
Geoff Langef7b0162014-09-04 13:29:23 -0400654 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
655 if (error.isError())
656 {
657 return error;
658 }
659
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700660 mDirtyImages = true;
661 }
662 else
663 {
Geoff Langef7b0162014-09-04 13:29:23 -0400664 gl::Error error = ensureRenderTarget();
665 if (error.isError())
666 {
667 return error;
668 }
669
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700670 mImageArray[level]->markClean();
671
672 if (width != 0 && height != 0 && isValidLevel(level))
673 {
Geoff Langef7b0162014-09-04 13:29:23 -0400674 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
675 if (error.isError())
676 {
677 return error;
678 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700679 }
680 }
Geoff Langef7b0162014-09-04 13:29:23 -0400681
682 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700683}
684
Geoff Langef7b0162014-09-04 13:29:23 -0400685gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
686 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700687{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700688 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
689
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700690 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
691 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700692
Jamie Madill82bf0c52014-10-03 11:50:53 -0400693 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400694 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400695
Jamie Madille76bdda2014-10-20 17:13:52 -0400696 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700697 {
Geoff Langef7b0162014-09-04 13:29:23 -0400698 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
699 if (error.isError())
700 {
701 return error;
702 }
703
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704 mDirtyImages = true;
705 }
706 else
707 {
Geoff Langef7b0162014-09-04 13:29:23 -0400708 gl::Error error = ensureRenderTarget();
709 if (error.isError())
710 {
711 return error;
712 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700713
714 if (isValidLevel(level))
715 {
Geoff Langef7b0162014-09-04 13:29:23 -0400716 error = updateStorageLevel(level);
717 if (error.isError())
718 {
719 return error;
720 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700721
Geoff Langef7b0162014-09-04 13:29:23 -0400722 error = mRenderer->copyImage2D(source, sourceRect,
723 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
724 xoffset, yoffset, mTexStorage, level);
725 if (error.isError())
726 {
727 return error;
728 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700729 }
730 }
Geoff Langef7b0162014-09-04 13:29:23 -0400731
732 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733}
734
Geoff Lang1f8532b2014-09-05 09:46:13 -0400735gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700736{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700737 ASSERT(target == GL_TEXTURE_2D && depth == 1);
738
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700739 for (int level = 0; level < levels; level++)
740 {
741 GLsizei levelWidth = std::max(1, width >> level);
742 GLsizei levelHeight = std::max(1, height >> level);
743 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
744 }
745
746 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
747 {
748 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
749 }
750
Geoff Lang1f8532b2014-09-05 09:46:13 -0400751 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400752 bool renderTarget = IsRenderTargetUsage(mUsage);
753 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400754
755 gl::Error error = setCompleteTexStorage(storage);
756 if (error.isError())
757 {
758 SafeDelete(storage);
759 return error;
760 }
761
762 mImmutable = true;
763
764 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765}
766
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700767void TextureD3D_2D::bindTexImage(egl::Surface *surface)
768{
769 GLenum internalformat = surface->getFormat();
770
771 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
772
773 if (mTexStorage)
774 {
775 SafeDelete(mTexStorage);
776 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400777
778 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700779
780 mDirtyImages = true;
781}
782
783void TextureD3D_2D::releaseTexImage()
784{
785 if (mTexStorage)
786 {
787 SafeDelete(mTexStorage);
788 }
789
790 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
791 {
792 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
793 }
794}
795
Jamie Madill4aa79e12014-09-29 10:46:14 -0400796void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700797{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700798 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700799 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700800 for (int level = 1; level < levelCount; level++)
801 {
802 redefineImage(level, getBaseLevelInternalFormat(),
803 std::max(getBaseLevelWidth() >> level, 1),
804 std::max(getBaseLevelHeight() >> level, 1));
805 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700806}
807
Jamie Madillac7579c2014-09-17 16:59:33 -0400808unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809{
Jamie Madillac7579c2014-09-17 16:59:33 -0400810 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400811 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812}
813
Geoff Lang64f23f62014-09-10 14:40:12 -0400814gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700815{
Jamie Madillac7579c2014-09-17 16:59:33 -0400816 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700818 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400819 gl::Error error = ensureRenderTarget();
820 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700821 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400822 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700823 }
824
Geoff Langef7b0162014-09-04 13:29:23 -0400825 error = updateStorageLevel(index.mipIndex);
826 if (error.isError())
827 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400828 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400829 }
830
Geoff Lang64f23f62014-09-10 14:40:12 -0400831 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700832}
833
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700834bool TextureD3D_2D::isValidLevel(int level) const
835{
836 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
837}
838
839bool TextureD3D_2D::isLevelComplete(int level) const
840{
841 if (isImmutable())
842 {
843 return true;
844 }
845
Brandon Jones78b1acd2014-07-15 15:33:07 -0700846 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700847
848 GLsizei width = baseImage->getWidth();
849 GLsizei height = baseImage->getHeight();
850
851 if (width <= 0 || height <= 0)
852 {
853 return false;
854 }
855
856 // The base image level is complete if the width and height are positive
857 if (level == 0)
858 {
859 return true;
860 }
861
862 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700863 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700864
865 if (image->getInternalFormat() != baseImage->getInternalFormat())
866 {
867 return false;
868 }
869
870 if (image->getWidth() != std::max(1, width >> level))
871 {
872 return false;
873 }
874
875 if (image->getHeight() != std::max(1, height >> level))
876 {
877 return false;
878 }
879
880 return true;
881}
882
Jamie Madille76bdda2014-10-20 17:13:52 -0400883bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
884{
885 return isLevelComplete(index.mipIndex);
886}
887
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700888// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400889gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700890{
891 // Only initialize the first time this texture is used as a render target or shader resource
892 if (mTexStorage)
893 {
Geoff Langef7b0162014-09-04 13:29:23 -0400894 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700895 }
896
897 // do not attempt to create storage for nonexistant data
898 if (!isLevelComplete(0))
899 {
Geoff Langef7b0162014-09-04 13:29:23 -0400900 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700901 }
902
903 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
904
Geoff Langef7b0162014-09-04 13:29:23 -0400905 TextureStorage *storage = NULL;
906 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
907 if (error.isError())
908 {
909 return error;
910 }
911
912 error = setCompleteTexStorage(storage);
913 if (error.isError())
914 {
915 SafeDelete(storage);
916 return error;
917 }
918
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919 ASSERT(mTexStorage);
920
921 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400922 error = updateStorage();
923 if (error.isError())
924 {
925 return error;
926 }
927
928 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700929}
930
Geoff Langef7b0162014-09-04 13:29:23 -0400931gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700932{
933 GLsizei width = getBaseLevelWidth();
934 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400935 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700936
937 ASSERT(width > 0 && height > 0);
938
939 // use existing storage level count, when previously specified by TexStorage*D
940 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
941
Geoff Langef7b0162014-09-04 13:29:23 -0400942 // TODO(geofflang): Determine if the texture creation succeeded
943 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
944
945 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700946}
947
Geoff Langef7b0162014-09-04 13:29:23 -0400948gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700949{
Geoff Langef7b0162014-09-04 13:29:23 -0400950 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700951 {
Geoff Langef7b0162014-09-04 13:29:23 -0400952 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700953 {
Geoff Langef7b0162014-09-04 13:29:23 -0400954 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
955 if (error.isError())
956 {
957 return error;
958 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700959 }
960 }
961
Geoff Langef7b0162014-09-04 13:29:23 -0400962 SafeDelete(mTexStorage);
963 mTexStorage = newCompleteTexStorage;
964
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700965 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400966
967 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700968}
969
Geoff Langef7b0162014-09-04 13:29:23 -0400970gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700971{
972 ASSERT(mTexStorage != NULL);
973 GLint storageLevels = mTexStorage->getLevelCount();
974 for (int level = 0; level < storageLevels; level++)
975 {
976 if (mImageArray[level]->isDirty() && isLevelComplete(level))
977 {
Geoff Langef7b0162014-09-04 13:29:23 -0400978 gl::Error error = updateStorageLevel(level);
979 if (error.isError())
980 {
981 return error;
982 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700983 }
984 }
Geoff Langef7b0162014-09-04 13:29:23 -0400985
986 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700987}
988
Geoff Langef7b0162014-09-04 13:29:23 -0400989gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990{
991 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
992 ASSERT(isLevelComplete(level));
993
994 if (mImageArray[level]->isDirty())
995 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400996 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
997 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -0400998 gl::Error error = commitRegion(index, region);
999 if (error.isError())
1000 {
1001 return error;
1002 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001003 }
Geoff Langef7b0162014-09-04 13:29:23 -04001004
1005 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001006}
1007
1008void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1009{
1010 // If there currently is a corresponding storage texture image, it has these parameters
1011 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1012 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1013 const GLenum storageFormat = getBaseLevelInternalFormat();
1014
1015 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1016
1017 if (mTexStorage)
1018 {
1019 const int storageLevels = mTexStorage->getLevelCount();
1020
1021 if ((level >= storageLevels && storageLevels != 0) ||
1022 width != storageWidth ||
1023 height != storageHeight ||
1024 internalformat != storageFormat) // Discard mismatched storage
1025 {
1026 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1027 {
1028 mImageArray[i]->markDirty();
1029 }
1030
1031 SafeDelete(mTexStorage);
1032 mDirtyImages = true;
1033 }
1034 }
1035}
1036
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001037gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001038{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001039 ASSERT(!index.hasLayer());
1040 GLint level = index.mipIndex;
1041
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001042 if (isValidLevel(level))
1043 {
Brandon Jones78b1acd2014-07-15 15:33:07 -07001044 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001045 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001046 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001047 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001048 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001049 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001050
1051 image->markClean();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001052 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001053
1054 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001055}
1056
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001057gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1058{
1059 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1060}
Brandon Jones0511e802014-07-14 16:27:26 -07001061
Jamie Madillcb83dc12014-09-29 10:46:12 -04001062gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1063{
1064 // "layer" does not apply to 2D Textures.
1065 return gl::ImageIndex::Make2D(mip);
1066}
1067
Brandon Jones78b1acd2014-07-15 15:33:07 -07001068TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001069 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001070{
1071 for (int i = 0; i < 6; i++)
1072 {
1073 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1074 {
1075 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1076 }
1077 }
1078}
1079
1080TextureD3D_Cube::~TextureD3D_Cube()
1081{
Austin Kinross69822602014-08-12 15:51:37 -07001082 // Delete the Images before the TextureStorage.
1083 // Images might be relying on the TextureStorage for some of their data.
1084 // 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 -07001085 for (int i = 0; i < 6; i++)
1086 {
1087 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1088 {
1089 SafeDelete(mImageArray[i][j]);
1090 }
1091 }
Austin Kinross69822602014-08-12 15:51:37 -07001092
1093 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001094}
1095
Brandon Jonescef06ff2014-08-05 13:27:48 -07001096Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001097{
1098 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001099 ASSERT(layer < 6);
1100 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001101}
1102
Jamie Madillfeda4d22014-09-17 13:03:29 -04001103Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1104{
1105 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1106 ASSERT(index.layerIndex < 6);
1107 return mImageArray[index.layerIndex][index.mipIndex];
1108}
1109
Brandon Jonescef06ff2014-08-05 13:27:48 -07001110GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001111{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001112 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1113 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001114}
1115
Brandon Jonescef06ff2014-08-05 13:27:48 -07001116GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001117{
1118 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001119 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001120 else
1121 return GL_NONE;
1122}
1123
Brandon Jonescef06ff2014-08-05 13:27:48 -07001124bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001125{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001126 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001127}
1128
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001129gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1130 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1131 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001133 ASSERT(depth == 1);
1134
Geoff Lang5d601382014-07-22 15:14:06 -04001135 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001136 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001137
Jamie Madillba6bc952014-10-06 10:56:22 -04001138 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001139
Jamie Madillba6bc952014-10-06 10:56:22 -04001140 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001141}
1142
Geoff Langb5348332014-09-02 13:16:34 -04001143gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1144 GLsizei width, GLsizei height, GLsizei depth,
1145 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001146{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001147 ASSERT(depth == 1);
1148
Brandon Jones0511e802014-07-14 16:27:26 -07001149 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001150 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1151
Brandon Jones0511e802014-07-14 16:27:26 -07001152 redefineImage(faceIndex, level, format, width, height);
1153
Geoff Langb5348332014-09-02 13:16:34 -04001154 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001155}
1156
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001157gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1158 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1159 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001160{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001161 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001162 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001163 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001164}
1165
Geoff Langb5348332014-09-02 13:16:34 -04001166gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1167 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1168 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001169{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001170 ASSERT(depth == 1 && zoffset == 0);
1171
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001172 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001173
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001174 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 -04001175 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001176 {
Geoff Langb5348332014-09-02 13:16:34 -04001177 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001178 }
Geoff Langb5348332014-09-02 13:16:34 -04001179
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001180 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1181 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001182}
1183
Geoff Langef7b0162014-09-04 13:29:23 -04001184gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1185 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001186{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001187 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001188 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1189
Brandon Jones0511e802014-07-14 16:27:26 -07001190 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1191
Jamie Madill82bf0c52014-10-03 11:50:53 -04001192 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001193 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001194
Jamie Madille76bdda2014-10-20 17:13:52 -04001195 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001196 {
Geoff Langef7b0162014-09-04 13:29:23 -04001197 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1198 if (error.isError())
1199 {
1200 return error;
1201 }
1202
Brandon Jones0511e802014-07-14 16:27:26 -07001203 mDirtyImages = true;
1204 }
1205 else
1206 {
Geoff Langef7b0162014-09-04 13:29:23 -04001207 gl::Error error = ensureRenderTarget();
1208 if (error.isError())
1209 {
1210 return error;
1211 }
1212
Brandon Jones0511e802014-07-14 16:27:26 -07001213 mImageArray[faceIndex][level]->markClean();
1214
1215 ASSERT(width == height);
1216
1217 if (width > 0 && isValidFaceLevel(faceIndex, level))
1218 {
Geoff Langef7b0162014-09-04 13:29:23 -04001219 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1220 if (error.isError())
1221 {
1222 return error;
1223 }
Brandon Jones0511e802014-07-14 16:27:26 -07001224 }
1225 }
Geoff Langef7b0162014-09-04 13:29:23 -04001226
1227 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001228}
1229
Geoff Langef7b0162014-09-04 13:29:23 -04001230gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1231 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001232{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001233 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001234
Jamie Madill82bf0c52014-10-03 11:50:53 -04001235 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001236 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001237
Jamie Madille76bdda2014-10-20 17:13:52 -04001238 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001239 {
Geoff Langef7b0162014-09-04 13:29:23 -04001240 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1241 if (error.isError())
1242 {
1243 return error;
1244 }
1245
Brandon Jones0511e802014-07-14 16:27:26 -07001246 mDirtyImages = true;
1247 }
1248 else
1249 {
Geoff Langef7b0162014-09-04 13:29:23 -04001250 gl::Error error = ensureRenderTarget();
1251 if (error.isError())
1252 {
1253 return error;
1254 }
Brandon Jones0511e802014-07-14 16:27:26 -07001255
1256 if (isValidFaceLevel(faceIndex, level))
1257 {
Geoff Langef7b0162014-09-04 13:29:23 -04001258 error = updateStorageFaceLevel(faceIndex, level);
1259 if (error.isError())
1260 {
1261 return error;
1262 }
Brandon Jones0511e802014-07-14 16:27:26 -07001263
Geoff Langef7b0162014-09-04 13:29:23 -04001264 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1265 xoffset, yoffset, mTexStorage, target, level);
1266 if (error.isError())
1267 {
1268 return error;
1269 }
Brandon Jones0511e802014-07-14 16:27:26 -07001270 }
1271 }
Geoff Langef7b0162014-09-04 13:29:23 -04001272
1273 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001274}
1275
Geoff Lang1f8532b2014-09-05 09:46:13 -04001276gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001277{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001278 ASSERT(width == height);
1279 ASSERT(depth == 1);
1280
Brandon Jones0511e802014-07-14 16:27:26 -07001281 for (int level = 0; level < levels; level++)
1282 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001283 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001284 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1285 {
1286 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1287 }
1288 }
1289
1290 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1291 {
1292 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1293 {
1294 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1295 }
1296 }
1297
Geoff Lang1f8532b2014-09-05 09:46:13 -04001298 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001299 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001300 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001301
1302 gl::Error error = setCompleteTexStorage(storage);
1303 if (error.isError())
1304 {
1305 SafeDelete(storage);
1306 return error;
1307 }
1308
1309 mImmutable = true;
1310
1311 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001312}
1313
Brandon Jones0511e802014-07-14 16:27:26 -07001314// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1315bool TextureD3D_Cube::isCubeComplete() const
1316{
1317 int baseWidth = getBaseLevelWidth();
1318 int baseHeight = getBaseLevelHeight();
1319 GLenum baseFormat = getBaseLevelInternalFormat();
1320
1321 if (baseWidth <= 0 || baseWidth != baseHeight)
1322 {
1323 return false;
1324 }
1325
1326 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1327 {
1328 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1329
1330 if (faceBaseImage.getWidth() != baseWidth ||
1331 faceBaseImage.getHeight() != baseHeight ||
1332 faceBaseImage.getInternalFormat() != baseFormat )
1333 {
1334 return false;
1335 }
1336 }
1337
1338 return true;
1339}
1340
Brandon Jones6053a522014-07-25 16:22:09 -07001341void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1342{
1343 UNREACHABLE();
1344}
1345
1346void TextureD3D_Cube::releaseTexImage()
1347{
1348 UNREACHABLE();
1349}
1350
1351
Jamie Madill4aa79e12014-09-29 10:46:14 -04001352void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001353{
1354 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1355 int levelCount = mipLevels();
1356 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1357 {
1358 for (int level = 1; level < levelCount; level++)
1359 {
1360 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1361 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1362 }
1363 }
Brandon Jones0511e802014-07-14 16:27:26 -07001364}
1365
Jamie Madillac7579c2014-09-17 16:59:33 -04001366unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001367{
Geoff Langef7b0162014-09-04 13:29:23 -04001368 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001369}
1370
Geoff Lang64f23f62014-09-10 14:40:12 -04001371gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001372{
Jamie Madillac7579c2014-09-17 16:59:33 -04001373 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001374
1375 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001376 gl::Error error = ensureRenderTarget();
1377 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001378 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001379 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001380 }
1381
Geoff Langef7b0162014-09-04 13:29:23 -04001382 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1383 if (error.isError())
1384 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001385 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001386 }
1387
Geoff Lang64f23f62014-09-10 14:40:12 -04001388 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001389}
1390
Geoff Langef7b0162014-09-04 13:29:23 -04001391gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001392{
1393 // Only initialize the first time this texture is used as a render target or shader resource
1394 if (mTexStorage)
1395 {
Geoff Langef7b0162014-09-04 13:29:23 -04001396 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001397 }
1398
1399 // do not attempt to create storage for nonexistant data
1400 if (!isFaceLevelComplete(0, 0))
1401 {
Geoff Langef7b0162014-09-04 13:29:23 -04001402 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001403 }
1404
1405 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1406
Geoff Langef7b0162014-09-04 13:29:23 -04001407 TextureStorage *storage = NULL;
1408 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1409 if (error.isError())
1410 {
1411 return error;
1412 }
1413
1414 error = setCompleteTexStorage(storage);
1415 if (error.isError())
1416 {
1417 SafeDelete(storage);
1418 return error;
1419 }
1420
Brandon Jones0511e802014-07-14 16:27:26 -07001421 ASSERT(mTexStorage);
1422
1423 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001424 error = updateStorage();
1425 if (error.isError())
1426 {
1427 return error;
1428 }
1429
1430 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001431}
1432
Geoff Langef7b0162014-09-04 13:29:23 -04001433gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001434{
1435 GLsizei size = getBaseLevelWidth();
1436
1437 ASSERT(size > 0);
1438
1439 // use existing storage level count, when previously specified by TexStorage*D
1440 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1441
Geoff Langef7b0162014-09-04 13:29:23 -04001442 // TODO (geofflang): detect if storage creation succeeded
1443 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1444
1445 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001446}
1447
Geoff Langef7b0162014-09-04 13:29:23 -04001448gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001449{
Geoff Langef7b0162014-09-04 13:29:23 -04001450 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001451 {
1452 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1453 {
Geoff Langef7b0162014-09-04 13:29:23 -04001454 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001455 {
Geoff Langef7b0162014-09-04 13:29:23 -04001456 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1457 if (error.isError())
1458 {
1459 return error;
1460 }
Brandon Jones0511e802014-07-14 16:27:26 -07001461 }
1462 }
1463 }
1464
Geoff Langef7b0162014-09-04 13:29:23 -04001465 SafeDelete(mTexStorage);
1466 mTexStorage = newCompleteTexStorage;
1467
Brandon Jones0511e802014-07-14 16:27:26 -07001468 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001469 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001470}
1471
Geoff Langef7b0162014-09-04 13:29:23 -04001472gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001473{
1474 ASSERT(mTexStorage != NULL);
1475 GLint storageLevels = mTexStorage->getLevelCount();
1476 for (int face = 0; face < 6; face++)
1477 {
1478 for (int level = 0; level < storageLevels; level++)
1479 {
1480 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1481 {
Geoff Langef7b0162014-09-04 13:29:23 -04001482 gl::Error error = updateStorageFaceLevel(face, level);
1483 if (error.isError())
1484 {
1485 return error;
1486 }
Brandon Jones0511e802014-07-14 16:27:26 -07001487 }
1488 }
1489 }
Geoff Langef7b0162014-09-04 13:29:23 -04001490
1491 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001492}
1493
Brandon Jones0511e802014-07-14 16:27:26 -07001494bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1495{
1496 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1497}
1498
Brandon Jones0511e802014-07-14 16:27:26 -07001499bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1500{
1501 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1502
1503 if (isImmutable())
1504 {
1505 return true;
1506 }
1507
1508 int baseSize = getBaseLevelWidth();
1509
1510 if (baseSize <= 0)
1511 {
1512 return false;
1513 }
1514
1515 // "isCubeComplete" checks for base level completeness and we must call that
1516 // to determine if any face at level 0 is complete. We omit that check here
1517 // to avoid re-checking cube-completeness for every face at level 0.
1518 if (level == 0)
1519 {
1520 return true;
1521 }
1522
1523 // Check that non-zero levels are consistent with the base level.
1524 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1525
1526 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1527 {
1528 return false;
1529 }
1530
1531 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1532 {
1533 return false;
1534 }
1535
1536 return true;
1537}
1538
Jamie Madille76bdda2014-10-20 17:13:52 -04001539bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1540{
1541 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1542}
1543
Geoff Langef7b0162014-09-04 13:29:23 -04001544gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001545{
1546 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1547 ImageD3D *image = mImageArray[faceIndex][level];
1548
1549 if (image->isDirty())
1550 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001551 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1552 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1553 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001554 gl::Error error = commitRegion(index, region);
1555 if (error.isError())
1556 {
1557 return error;
1558 }
Brandon Jones0511e802014-07-14 16:27:26 -07001559 }
Geoff Langef7b0162014-09-04 13:29:23 -04001560
1561 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001562}
1563
1564void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1565{
1566 // If there currently is a corresponding storage texture image, it has these parameters
1567 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1568 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1569 const GLenum storageFormat = getBaseLevelInternalFormat();
1570
1571 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1572
1573 if (mTexStorage)
1574 {
1575 const int storageLevels = mTexStorage->getLevelCount();
1576
1577 if ((level >= storageLevels && storageLevels != 0) ||
1578 width != storageWidth ||
1579 height != storageHeight ||
1580 internalformat != storageFormat) // Discard mismatched storage
1581 {
1582 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1583 {
1584 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1585 {
1586 mImageArray[faceIndex][level]->markDirty();
1587 }
1588 }
1589
1590 SafeDelete(mTexStorage);
1591
1592 mDirtyImages = true;
1593 }
1594 }
1595}
1596
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001597gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones0511e802014-07-14 16:27:26 -07001598{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001599 ASSERT(index.hasLayer());
1600
1601 GLint level = index.mipIndex;
1602 int faceIndex = static_cast<int>(index.layerIndex);
1603
Brandon Jones0511e802014-07-14 16:27:26 -07001604 if (isValidFaceLevel(faceIndex, level))
1605 {
1606 ImageD3D *image = mImageArray[faceIndex][level];
Jamie Madill433bfd32014-10-20 12:07:36 -04001607 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001608 if (error.isError())
1609 {
1610 return error;
1611 }
1612
1613 image->markClean();
Brandon Jones0511e802014-07-14 16:27:26 -07001614 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001615
1616 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001617}
1618
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001619gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1620{
1621 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1622}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001623
Jamie Madillcb83dc12014-09-29 10:46:12 -04001624gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1625{
1626 // The "layer" of the image index corresponds to the cube face
1627 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1628}
1629
Brandon Jones78b1acd2014-07-15 15:33:07 -07001630TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001631 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001632{
1633 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1634 {
1635 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1636 }
1637}
1638
1639TextureD3D_3D::~TextureD3D_3D()
1640{
Austin Kinross69822602014-08-12 15:51:37 -07001641 // Delete the Images before the TextureStorage.
1642 // Images might be relying on the TextureStorage for some of their data.
1643 // 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 -07001644 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1645 {
1646 delete mImageArray[i];
1647 }
Austin Kinross69822602014-08-12 15:51:37 -07001648
1649 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001650}
1651
Brandon Jonescef06ff2014-08-05 13:27:48 -07001652Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001653{
1654 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001655 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656 return mImageArray[level];
1657}
1658
Jamie Madillfeda4d22014-09-17 13:03:29 -04001659Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1660{
1661 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001662 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001663 ASSERT(index.type == GL_TEXTURE_3D);
1664 return mImageArray[index.mipIndex];
1665}
1666
Brandon Jonescef06ff2014-08-05 13:27:48 -07001667GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001668{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001669 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1670 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001671}
1672
Brandon Jones78b1acd2014-07-15 15:33:07 -07001673GLsizei TextureD3D_3D::getWidth(GLint level) const
1674{
1675 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1676 return mImageArray[level]->getWidth();
1677 else
1678 return 0;
1679}
1680
1681GLsizei TextureD3D_3D::getHeight(GLint level) const
1682{
1683 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1684 return mImageArray[level]->getHeight();
1685 else
1686 return 0;
1687}
1688
1689GLsizei TextureD3D_3D::getDepth(GLint level) const
1690{
1691 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1692 return mImageArray[level]->getDepth();
1693 else
1694 return 0;
1695}
1696
1697GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1698{
1699 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1700 return mImageArray[level]->getInternalFormat();
1701 else
1702 return GL_NONE;
1703}
1704
1705bool TextureD3D_3D::isDepth(GLint level) const
1706{
Geoff Lang5d601382014-07-22 15:14:06 -04001707 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001708}
1709
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001710gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1711 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1712 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001713{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001714 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001715 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1716
Brandon Jones78b1acd2014-07-15 15:33:07 -07001717 redefineImage(level, sizedInternalFormat, width, height, depth);
1718
1719 bool fastUnpacked = false;
1720
Jamie Madillba6bc952014-10-06 10:56:22 -04001721 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1722
Brandon Jones78b1acd2014-07-15 15:33:07 -07001723 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1724 if (isFastUnpackable(unpack, sizedInternalFormat))
1725 {
1726 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001727 RenderTarget *destRenderTarget = NULL;
1728 gl::Error error = getRenderTarget(index, &destRenderTarget);
1729 if (error.isError())
1730 {
1731 return error;
1732 }
1733
Brandon Jones78b1acd2014-07-15 15:33:07 -07001734 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1735
Geoff Lang64f23f62014-09-10 14:40:12 -04001736 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1737 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001738 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001739 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001740 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001741
1742 // Ensure we don't overwrite our newly initialized data
1743 mImageArray[level]->markClean();
1744
1745 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001746 }
1747
1748 if (!fastUnpacked)
1749 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001750 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001751 if (error.isError())
1752 {
1753 return error;
1754 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001755 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001756
1757 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758}
1759
Geoff Langb5348332014-09-02 13:16:34 -04001760gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1761 GLsizei width, GLsizei height,GLsizei depth,
1762 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001763{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001764 ASSERT(target == GL_TEXTURE_3D);
1765
Brandon Jones78b1acd2014-07-15 15:33:07 -07001766 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1767 redefineImage(level, format, width, height, depth);
1768
Geoff Langb5348332014-09-02 13:16:34 -04001769 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001770}
1771
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001772gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1773 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1774 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001775{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001776 ASSERT(target == GL_TEXTURE_3D);
1777
Brandon Jones78b1acd2014-07-15 15:33:07 -07001778 bool fastUnpacked = false;
1779
Jamie Madillac7579c2014-09-17 16:59:33 -04001780 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1781
Brandon Jones78b1acd2014-07-15 15:33:07 -07001782 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1783 if (isFastUnpackable(unpack, getInternalFormat(level)))
1784 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001785 RenderTarget *destRenderTarget = NULL;
1786 gl::Error error = getRenderTarget(index, &destRenderTarget);
1787 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001788 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001789 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001790 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001791
1792 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1793 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1794 if (error.isError())
1795 {
1796 return error;
1797 }
1798
1799 // Ensure we don't overwrite our newly initialized data
1800 mImageArray[level]->markClean();
1801
1802 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001803 }
1804
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001805 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001807 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1808 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001810
1811 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812}
1813
Geoff Langb5348332014-09-02 13:16:34 -04001814gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1815 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1816 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001817{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001818 ASSERT(target == GL_TEXTURE_3D);
1819
Geoff Langb5348332014-09-02 13:16:34 -04001820 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1821 format, imageSize, pixels, mImageArray[level]);
1822 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001823 {
Geoff Langb5348332014-09-02 13:16:34 -04001824 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001825 }
Geoff Langb5348332014-09-02 13:16:34 -04001826
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001827 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1828 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1829 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830}
1831
Geoff Langef7b0162014-09-04 13:29:23 -04001832gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1833 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001834{
1835 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001836 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001837}
1838
Geoff Langef7b0162014-09-04 13:29:23 -04001839gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1840 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001841{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001842 ASSERT(target == GL_TEXTURE_3D);
1843
Jamie Madill82bf0c52014-10-03 11:50:53 -04001844 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001845 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001846
Jamie Madille76bdda2014-10-20 17:13:52 -04001847 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001848 {
Geoff Langef7b0162014-09-04 13:29:23 -04001849 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1850 if (error.isError())
1851 {
1852 return error;
1853 }
1854
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855 mDirtyImages = true;
1856 }
1857 else
1858 {
Geoff Langef7b0162014-09-04 13:29:23 -04001859 gl::Error error = ensureRenderTarget();
1860 if (error.isError())
1861 {
1862 return error;
1863 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001864
1865 if (isValidLevel(level))
1866 {
Geoff Langef7b0162014-09-04 13:29:23 -04001867 error = updateStorageLevel(level);
1868 if (error.isError())
1869 {
1870 return error;
1871 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001872
Geoff Langef7b0162014-09-04 13:29:23 -04001873 error = mRenderer->copyImage3D(source, sourceRect,
1874 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1875 xoffset, yoffset, zoffset, mTexStorage, level);
1876 if (error.isError())
1877 {
1878 return error;
1879 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001880 }
1881 }
Geoff Langef7b0162014-09-04 13:29:23 -04001882
1883 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001884}
1885
Geoff Lang1f8532b2014-09-05 09:46:13 -04001886gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001887{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001888 ASSERT(target == GL_TEXTURE_3D);
1889
Brandon Jones78b1acd2014-07-15 15:33:07 -07001890 for (int level = 0; level < levels; level++)
1891 {
1892 GLsizei levelWidth = std::max(1, width >> level);
1893 GLsizei levelHeight = std::max(1, height >> level);
1894 GLsizei levelDepth = std::max(1, depth >> level);
1895 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1896 }
1897
1898 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1899 {
1900 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1901 }
1902
Geoff Lang1f8532b2014-09-05 09:46:13 -04001903 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001904 bool renderTarget = IsRenderTargetUsage(mUsage);
1905 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001906
1907 gl::Error error = setCompleteTexStorage(storage);
1908 if (error.isError())
1909 {
1910 SafeDelete(storage);
1911 return error;
1912 }
1913
1914 mImmutable = true;
1915
1916 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917}
1918
Brandon Jones6053a522014-07-25 16:22:09 -07001919void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001920{
Brandon Jones6053a522014-07-25 16:22:09 -07001921 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001922}
1923
Brandon Jones6053a522014-07-25 16:22:09 -07001924void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001925{
Brandon Jones6053a522014-07-25 16:22:09 -07001926 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001927}
1928
Brandon Jones6053a522014-07-25 16:22:09 -07001929
Jamie Madill4aa79e12014-09-29 10:46:14 -04001930void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001931{
1932 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1933 int levelCount = mipLevels();
1934 for (int level = 1; level < levelCount; level++)
1935 {
1936 redefineImage(level, getBaseLevelInternalFormat(),
1937 std::max(getBaseLevelWidth() >> level, 1),
1938 std::max(getBaseLevelHeight() >> level, 1),
1939 std::max(getBaseLevelDepth() >> level, 1));
1940 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001941}
1942
Jamie Madillac7579c2014-09-17 16:59:33 -04001943unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001944{
Geoff Langef7b0162014-09-04 13:29:23 -04001945 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001946}
1947
Geoff Lang64f23f62014-09-10 14:40:12 -04001948gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949{
1950 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001951 gl::Error error = ensureRenderTarget();
1952 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001953 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001954 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001955 }
1956
Jamie Madillac7579c2014-09-17 16:59:33 -04001957 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001958 {
Geoff Langef7b0162014-09-04 13:29:23 -04001959 error = updateStorage();
1960 if (error.isError())
1961 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001962 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001963 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001964 }
1965 else
1966 {
Geoff Langef7b0162014-09-04 13:29:23 -04001967 error = updateStorageLevel(index.mipIndex);
1968 if (error.isError())
1969 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001970 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001971 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001972 }
1973
Geoff Lang64f23f62014-09-10 14:40:12 -04001974 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001975}
1976
Geoff Langef7b0162014-09-04 13:29:23 -04001977gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001978{
1979 // Only initialize the first time this texture is used as a render target or shader resource
1980 if (mTexStorage)
1981 {
Geoff Langef7b0162014-09-04 13:29:23 -04001982 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001983 }
1984
1985 // do not attempt to create storage for nonexistant data
1986 if (!isLevelComplete(0))
1987 {
Geoff Langef7b0162014-09-04 13:29:23 -04001988 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001989 }
1990
1991 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1992
Geoff Langef7b0162014-09-04 13:29:23 -04001993 rx::TextureStorage *storage = NULL;
1994 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1995 if (error.isError())
1996 {
1997 return error;
1998 }
1999
2000 error = setCompleteTexStorage(storage);
2001 if (error.isError())
2002 {
2003 SafeDelete(storage);
2004 return error;
2005 }
2006
Brandon Jones78b1acd2014-07-15 15:33:07 -07002007 ASSERT(mTexStorage);
2008
2009 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002010 error = updateStorage();
2011 if (error.isError())
2012 {
2013 return error;
2014 }
2015
2016 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002017}
2018
Geoff Langef7b0162014-09-04 13:29:23 -04002019gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020{
2021 GLsizei width = getBaseLevelWidth();
2022 GLsizei height = getBaseLevelHeight();
2023 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002024 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002025
2026 ASSERT(width > 0 && height > 0 && depth > 0);
2027
2028 // use existing storage level count, when previously specified by TexStorage*D
2029 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2030
Geoff Langef7b0162014-09-04 13:29:23 -04002031 // TODO: Verify creation of the storage succeeded
2032 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2033
2034 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002035}
2036
Geoff Langef7b0162014-09-04 13:29:23 -04002037gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002038{
2039 SafeDelete(mTexStorage);
2040 mTexStorage = newCompleteTexStorage;
2041 mDirtyImages = true;
2042
2043 // We do not support managed 3D storage, as that is D3D9/ES2-only
2044 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002045
2046 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002047}
2048
Geoff Langef7b0162014-09-04 13:29:23 -04002049gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002050{
2051 ASSERT(mTexStorage != NULL);
2052 GLint storageLevels = mTexStorage->getLevelCount();
2053 for (int level = 0; level < storageLevels; level++)
2054 {
2055 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2056 {
Geoff Langef7b0162014-09-04 13:29:23 -04002057 gl::Error error = updateStorageLevel(level);
2058 if (error.isError())
2059 {
2060 return error;
2061 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062 }
2063 }
Geoff Langef7b0162014-09-04 13:29:23 -04002064
2065 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002066}
2067
Brandon Jones78b1acd2014-07-15 15:33:07 -07002068bool TextureD3D_3D::isValidLevel(int level) const
2069{
2070 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2071}
2072
2073bool TextureD3D_3D::isLevelComplete(int level) const
2074{
2075 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2076
2077 if (isImmutable())
2078 {
2079 return true;
2080 }
2081
2082 GLsizei width = getBaseLevelWidth();
2083 GLsizei height = getBaseLevelHeight();
2084 GLsizei depth = getBaseLevelDepth();
2085
2086 if (width <= 0 || height <= 0 || depth <= 0)
2087 {
2088 return false;
2089 }
2090
2091 if (level == 0)
2092 {
2093 return true;
2094 }
2095
2096 ImageD3D *levelImage = mImageArray[level];
2097
2098 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2099 {
2100 return false;
2101 }
2102
2103 if (levelImage->getWidth() != std::max(1, width >> level))
2104 {
2105 return false;
2106 }
2107
2108 if (levelImage->getHeight() != std::max(1, height >> level))
2109 {
2110 return false;
2111 }
2112
2113 if (levelImage->getDepth() != std::max(1, depth >> level))
2114 {
2115 return false;
2116 }
2117
2118 return true;
2119}
2120
Jamie Madille76bdda2014-10-20 17:13:52 -04002121bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2122{
2123 return isLevelComplete(index.mipIndex);
2124}
2125
Geoff Langef7b0162014-09-04 13:29:23 -04002126gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002127{
2128 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2129 ASSERT(isLevelComplete(level));
2130
2131 if (mImageArray[level]->isDirty())
2132 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002133 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2134 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002135 gl::Error error = commitRegion(index, region);
2136 if (error.isError())
2137 {
2138 return error;
2139 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002140 }
Geoff Langef7b0162014-09-04 13:29:23 -04002141
2142 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002143}
2144
2145void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2146{
2147 // If there currently is a corresponding storage texture image, it has these parameters
2148 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2149 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2150 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2151 const GLenum storageFormat = getBaseLevelInternalFormat();
2152
2153 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2154
2155 if (mTexStorage)
2156 {
2157 const int storageLevels = mTexStorage->getLevelCount();
2158
2159 if ((level >= storageLevels && storageLevels != 0) ||
2160 width != storageWidth ||
2161 height != storageHeight ||
2162 depth != storageDepth ||
2163 internalformat != storageFormat) // Discard mismatched storage
2164 {
2165 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2166 {
2167 mImageArray[i]->markDirty();
2168 }
2169
2170 SafeDelete(mTexStorage);
2171 mDirtyImages = true;
2172 }
2173 }
2174}
2175
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002176gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002177{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002178 ASSERT(!index.hasLayer());
2179 GLint level = index.mipIndex;
2180
Brandon Jones78b1acd2014-07-15 15:33:07 -07002181 if (isValidLevel(level))
2182 {
2183 ImageD3D *image = mImageArray[level];
Jamie Madill433bfd32014-10-20 12:07:36 -04002184 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002185 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002186 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002187 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002188 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002189
2190 image->markClean();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002191 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002192
2193 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002194}
2195
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002196gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2197{
2198 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2199 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2200}
Brandon Jones142ec422014-07-16 10:31:30 -07002201
Jamie Madillcb83dc12014-09-29 10:46:12 -04002202gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2203{
2204 // The "layer" here does not apply to 3D images. We use one Image per mip.
2205 return gl::ImageIndex::Make3D(mip);
2206}
2207
Brandon Jones142ec422014-07-16 10:31:30 -07002208TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002209 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002210{
2211 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2212 {
2213 mLayerCounts[level] = 0;
2214 mImageArray[level] = NULL;
2215 }
2216}
2217
2218TextureD3D_2DArray::~TextureD3D_2DArray()
2219{
Austin Kinross69822602014-08-12 15:51:37 -07002220 // Delete the Images before the TextureStorage.
2221 // Images might be relying on the TextureStorage for some of their data.
2222 // 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 -07002223 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002224 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002225}
2226
Brandon Jones142ec422014-07-16 10:31:30 -07002227Image *TextureD3D_2DArray::getImage(int level, int layer) const
2228{
2229 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2230 ASSERT(layer < mLayerCounts[level]);
2231 return mImageArray[level][layer];
2232}
2233
Jamie Madillfeda4d22014-09-17 13:03:29 -04002234Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2235{
2236 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2237 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2238 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2239 return mImageArray[index.mipIndex][index.layerIndex];
2240}
2241
Brandon Jones142ec422014-07-16 10:31:30 -07002242GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2243{
2244 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2245 return mLayerCounts[level];
2246}
2247
Brandon Jones142ec422014-07-16 10:31:30 -07002248GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2249{
2250 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2251}
2252
2253GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2254{
2255 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2256}
2257
Brandon Jones142ec422014-07-16 10:31:30 -07002258GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2259{
2260 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2261}
2262
2263bool TextureD3D_2DArray::isDepth(GLint level) const
2264{
Geoff Lang5d601382014-07-22 15:14:06 -04002265 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002266}
2267
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002268gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2269 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2270 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002271{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002272 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2273
Geoff Lang5d601382014-07-22 15:14:06 -04002274 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2275
Brandon Jones142ec422014-07-16 10:31:30 -07002276 redefineImage(level, sizedInternalFormat, width, height, depth);
2277
Geoff Lang5d601382014-07-22 15:14:06 -04002278 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2279 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002280
2281 for (int i = 0; i < depth; i++)
2282 {
2283 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002284 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2285 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002286 if (error.isError())
2287 {
2288 return error;
2289 }
Brandon Jones142ec422014-07-16 10:31:30 -07002290 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002291
2292 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002293}
2294
Geoff Langb5348332014-09-02 13:16:34 -04002295gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2296 GLsizei width, GLsizei height, GLsizei depth,
2297 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002298{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002299 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2300
Brandon Jones142ec422014-07-16 10:31:30 -07002301 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2302 redefineImage(level, format, width, height, depth);
2303
Geoff Lang5d601382014-07-22 15:14:06 -04002304 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2305 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002306
2307 for (int i = 0; i < depth; i++)
2308 {
2309 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002310 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2311 if (error.isError())
2312 {
2313 return error;
2314 }
Brandon Jones142ec422014-07-16 10:31:30 -07002315 }
Geoff Langb5348332014-09-02 13:16:34 -04002316
2317 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002318}
2319
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002320gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2321 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2322 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002323{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002324 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2325
Geoff Lang5d601382014-07-22 15:14:06 -04002326 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2327 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002328
2329 for (int i = 0; i < depth; i++)
2330 {
2331 int layer = zoffset + i;
2332 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2333
Jamie Madillfeda4d22014-09-17 13:03:29 -04002334 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002335 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2336 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002337 if (error.isError())
2338 {
2339 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002340 }
2341 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002342
2343 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002344}
2345
Geoff Langb5348332014-09-02 13:16:34 -04002346gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2347 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2348 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002349{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002350 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2351
Geoff Lang5d601382014-07-22 15:14:06 -04002352 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2353 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002354
2355 for (int i = 0; i < depth; i++)
2356 {
2357 int layer = zoffset + i;
2358 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2359
Geoff Langb5348332014-09-02 13:16:34 -04002360 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2361 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002362 {
Geoff Langb5348332014-09-02 13:16:34 -04002363 return error;
2364 }
2365
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002366 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2367 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2368 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002369 if (error.isError())
2370 {
2371 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002372 }
2373 }
Geoff Langb5348332014-09-02 13:16:34 -04002374
2375 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002376}
2377
Geoff Langef7b0162014-09-04 13:29:23 -04002378gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002379{
2380 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002381 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002382}
2383
Geoff Langef7b0162014-09-04 13:29:23 -04002384gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002385{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002386 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2387
Jamie Madill82bf0c52014-10-03 11:50:53 -04002388 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002389 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002390
Jamie Madille76bdda2014-10-20 17:13:52 -04002391 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002392 {
Geoff Langef7b0162014-09-04 13:29:23 -04002393 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2394 if (error.isError())
2395 {
2396 return error;
2397 }
2398
Brandon Jones142ec422014-07-16 10:31:30 -07002399 mDirtyImages = true;
2400 }
2401 else
2402 {
Geoff Langef7b0162014-09-04 13:29:23 -04002403 gl::Error error = ensureRenderTarget();
2404 if (error.isError())
2405 {
2406 return error;
2407 }
Brandon Jones142ec422014-07-16 10:31:30 -07002408
2409 if (isValidLevel(level))
2410 {
Geoff Langef7b0162014-09-04 13:29:23 -04002411 error = updateStorageLevel(level);
2412 if (error.isError())
2413 {
2414 return error;
2415 }
Brandon Jones142ec422014-07-16 10:31:30 -07002416
Geoff Langef7b0162014-09-04 13:29:23 -04002417 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2418 xoffset, yoffset, zoffset, mTexStorage, level);
2419 if (error.isError())
2420 {
2421 return error;
2422 }
Brandon Jones142ec422014-07-16 10:31:30 -07002423 }
2424 }
Geoff Langef7b0162014-09-04 13:29:23 -04002425 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002426}
2427
Geoff Lang1f8532b2014-09-05 09:46:13 -04002428gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002429{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002430 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2431
Brandon Jones142ec422014-07-16 10:31:30 -07002432 deleteImages();
2433
2434 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2435 {
2436 GLsizei levelWidth = std::max(1, width >> level);
2437 GLsizei levelHeight = std::max(1, height >> level);
2438
2439 mLayerCounts[level] = (level < levels ? depth : 0);
2440
2441 if (mLayerCounts[level] > 0)
2442 {
2443 // Create new images for this level
2444 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2445
2446 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2447 {
2448 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2449 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2450 levelHeight, 1, true);
2451 }
2452 }
2453 }
2454
Geoff Lang1f8532b2014-09-05 09:46:13 -04002455 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002456 bool renderTarget = IsRenderTargetUsage(mUsage);
2457 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002458
2459 gl::Error error = setCompleteTexStorage(storage);
2460 if (error.isError())
2461 {
2462 SafeDelete(storage);
2463 return error;
2464 }
2465
2466 mImmutable = true;
2467
2468 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002469}
2470
Brandon Jones6053a522014-07-25 16:22:09 -07002471void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002472{
Brandon Jones6053a522014-07-25 16:22:09 -07002473 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002474}
2475
Brandon Jones6053a522014-07-25 16:22:09 -07002476void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002477{
Brandon Jones6053a522014-07-25 16:22:09 -07002478 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002479}
2480
Brandon Jones6053a522014-07-25 16:22:09 -07002481
Jamie Madill4aa79e12014-09-29 10:46:14 -04002482void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002483{
2484 int baseWidth = getBaseLevelWidth();
2485 int baseHeight = getBaseLevelHeight();
2486 int baseDepth = getBaseLevelDepth();
2487 GLenum baseFormat = getBaseLevelInternalFormat();
2488
2489 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2490 int levelCount = mipLevels();
2491 for (int level = 1; level < levelCount; level++)
2492 {
2493 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2494 }
Brandon Jones142ec422014-07-16 10:31:30 -07002495}
2496
Jamie Madillac7579c2014-09-17 16:59:33 -04002497unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002498{
Geoff Langef7b0162014-09-04 13:29:23 -04002499 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002500}
2501
Geoff Lang64f23f62014-09-10 14:40:12 -04002502gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002503{
2504 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002505 gl::Error error = ensureRenderTarget();
2506 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002507 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002508 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002509 }
2510
Geoff Langef7b0162014-09-04 13:29:23 -04002511 error = updateStorageLevel(index.mipIndex);
2512 if (error.isError())
2513 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002514 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002515 }
2516
Geoff Lang64f23f62014-09-10 14:40:12 -04002517 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002518}
2519
Geoff Langef7b0162014-09-04 13:29:23 -04002520gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002521{
2522 // Only initialize the first time this texture is used as a render target or shader resource
2523 if (mTexStorage)
2524 {
Geoff Langef7b0162014-09-04 13:29:23 -04002525 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002526 }
2527
2528 // do not attempt to create storage for nonexistant data
2529 if (!isLevelComplete(0))
2530 {
Geoff Langef7b0162014-09-04 13:29:23 -04002531 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002532 }
2533
2534 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2535
Geoff Langef7b0162014-09-04 13:29:23 -04002536 TextureStorage *storage = NULL;
2537 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2538 if (error.isError())
2539 {
2540 return error;
2541 }
2542
2543 error = setCompleteTexStorage(storage);
2544 if (error.isError())
2545 {
2546 SafeDelete(storage);
2547 return error;
2548 }
2549
Brandon Jones142ec422014-07-16 10:31:30 -07002550 ASSERT(mTexStorage);
2551
2552 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002553 error = updateStorage();
2554 if (error.isError())
2555 {
2556 return error;
2557 }
2558
2559 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002560}
2561
Geoff Langef7b0162014-09-04 13:29:23 -04002562gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002563{
2564 GLsizei width = getBaseLevelWidth();
2565 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002566 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002567 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002568
2569 ASSERT(width > 0 && height > 0 && depth > 0);
2570
2571 // use existing storage level count, when previously specified by TexStorage*D
2572 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2573
Geoff Langef7b0162014-09-04 13:29:23 -04002574 // TODO(geofflang): Verify storage creation succeeds
2575 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2576
2577 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002578}
2579
Geoff Langef7b0162014-09-04 13:29:23 -04002580gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002581{
2582 SafeDelete(mTexStorage);
2583 mTexStorage = newCompleteTexStorage;
2584 mDirtyImages = true;
2585
2586 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2587 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002588
2589 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002590}
2591
Geoff Langef7b0162014-09-04 13:29:23 -04002592gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002593{
2594 ASSERT(mTexStorage != NULL);
2595 GLint storageLevels = mTexStorage->getLevelCount();
2596 for (int level = 0; level < storageLevels; level++)
2597 {
2598 if (isLevelComplete(level))
2599 {
Geoff Langef7b0162014-09-04 13:29:23 -04002600 gl::Error error = updateStorageLevel(level);
2601 if (error.isError())
2602 {
2603 return error;
2604 }
Brandon Jones142ec422014-07-16 10:31:30 -07002605 }
2606 }
Geoff Langef7b0162014-09-04 13:29:23 -04002607
2608 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002609}
2610
Brandon Jones142ec422014-07-16 10:31:30 -07002611bool TextureD3D_2DArray::isValidLevel(int level) const
2612{
2613 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2614}
2615
2616bool TextureD3D_2DArray::isLevelComplete(int level) const
2617{
2618 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2619
2620 if (isImmutable())
2621 {
2622 return true;
2623 }
2624
2625 GLsizei width = getBaseLevelWidth();
2626 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002627 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002628
2629 if (width <= 0 || height <= 0 || layers <= 0)
2630 {
2631 return false;
2632 }
2633
2634 if (level == 0)
2635 {
2636 return true;
2637 }
2638
2639 if (getInternalFormat(level) != getInternalFormat(0))
2640 {
2641 return false;
2642 }
2643
2644 if (getWidth(level) != std::max(1, width >> level))
2645 {
2646 return false;
2647 }
2648
2649 if (getHeight(level) != std::max(1, height >> level))
2650 {
2651 return false;
2652 }
2653
Jamie Madill3269bcb2014-09-30 16:33:52 -04002654 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002655 {
2656 return false;
2657 }
2658
2659 return true;
2660}
2661
Jamie Madille76bdda2014-10-20 17:13:52 -04002662bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2663{
2664 return isLevelComplete(index.mipIndex);
2665}
2666
Geoff Langef7b0162014-09-04 13:29:23 -04002667gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002668{
2669 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2670 ASSERT(isLevelComplete(level));
2671
2672 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2673 {
2674 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2675 if (mImageArray[level][layer]->isDirty())
2676 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002677 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2678 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002679 gl::Error error = commitRegion(index, region);
2680 if (error.isError())
2681 {
2682 return error;
2683 }
Brandon Jones142ec422014-07-16 10:31:30 -07002684 }
2685 }
Geoff Langef7b0162014-09-04 13:29:23 -04002686
2687 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002688}
2689
2690void TextureD3D_2DArray::deleteImages()
2691{
2692 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2693 {
2694 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2695 {
2696 delete mImageArray[level][layer];
2697 }
2698 delete[] mImageArray[level];
2699 mImageArray[level] = NULL;
2700 mLayerCounts[level] = 0;
2701 }
2702}
2703
2704void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2705{
2706 // If there currently is a corresponding storage texture image, it has these parameters
2707 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2708 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002709 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002710 const GLenum storageFormat = getBaseLevelInternalFormat();
2711
2712 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2713 {
2714 delete mImageArray[level][layer];
2715 }
2716 delete[] mImageArray[level];
2717 mImageArray[level] = NULL;
2718 mLayerCounts[level] = depth;
2719
2720 if (depth > 0)
2721 {
2722 mImageArray[level] = new ImageD3D*[depth]();
2723
2724 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2725 {
2726 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2727 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2728 }
2729 }
2730
2731 if (mTexStorage)
2732 {
2733 const int storageLevels = mTexStorage->getLevelCount();
2734
2735 if ((level >= storageLevels && storageLevels != 0) ||
2736 width != storageWidth ||
2737 height != storageHeight ||
2738 depth != storageDepth ||
2739 internalformat != storageFormat) // Discard mismatched storage
2740 {
2741 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2742 {
2743 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2744 {
2745 mImageArray[level][layer]->markDirty();
2746 }
2747 }
2748
2749 delete mTexStorage;
2750 mTexStorage = NULL;
2751 mDirtyImages = true;
2752 }
2753 }
2754}
2755
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002756gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
Brandon Jones142ec422014-07-16 10:31:30 -07002757{
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002758 ASSERT(index.hasLayer());
2759 GLint level = index.mipIndex;
2760 GLint layerTarget = index.layerIndex;
2761
Jamie Madill3269bcb2014-09-30 16:33:52 -04002762 if (isValidLevel(level) && layerTarget < getLayerCount(level))
Brandon Jones142ec422014-07-16 10:31:30 -07002763 {
2764 ImageD3D *image = mImageArray[level][layerTarget];
Jamie Madill433bfd32014-10-20 12:07:36 -04002765 gl::Error error = image->copyToStorage(mTexStorage, index, region);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002766 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002767 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002768 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002769 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002770
2771 image->markClean();
Brandon Jones142ec422014-07-16 10:31:30 -07002772 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002773
2774 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002775}
2776
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002777gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2778{
2779 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2780}
2781
Jamie Madillcb83dc12014-09-29 10:46:12 -04002782gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2783{
2784 return gl::ImageIndex::Make2DArray(mip, layer);
2785}
2786
Brandon Jones78b1acd2014-07-15 15:33:07 -07002787}