blob: 42fea657a3d0cf49babe60ae65a1ef4be0384a11 [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.
Geoff Langc8d297a2014-09-19 11:09:08 -0400135 const uint8_t *bufferData = NULL;
136 gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
137 if (error.isError())
138 {
139 return error;
140 }
141 pixelData = bufferData + offset;
Jamie Madill9aca0592014-10-06 16:26:59 -0400142 }
143 else
144 {
145 pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700146 }
147
148 if (pixelData != NULL)
149 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400150 gl::Error error(GL_NO_ERROR);
151
Jamie Madillec6de4e2014-10-20 10:59:56 -0400152 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400153 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400154 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400155 }
156 else
157 {
158 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
159 }
160
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400161 if (error.isError())
162 {
163 return error;
164 }
165
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700166 mDirtyImages = true;
167 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400168
169 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700170}
171
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400172gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
173 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700174{
Jamie Madill9aca0592014-10-06 16:26:59 -0400175 const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700176
177 // CPU readback & copy where direct GPU copy is not supported
178 if (unpack.pixelBuffer.id() != 0)
179 {
180 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
Jacek Cabana5521de2014-10-01 17:23:46 +0200181 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700182 // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
183 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
Geoff Langc8d297a2014-09-19 11:09:08 -0400184 const uint8_t *bufferData = NULL;
185 gl::Error error = pixelBuffer->getImplementation()->getData(&bufferData);
186 if (error.isError())
187 {
188 return error;
189 }
190 pixelData = bufferData + offset;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700191 }
192
193 if (pixelData != NULL)
194 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400195 Image *image = getImage(index);
196 ASSERT(image);
197
Jamie Madill9aca0592014-10-06 16:26:59 -0400198 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400199 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400200 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400201 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400202 }
203
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400204 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
205 type, pixelData);
206 if (error.isError())
207 {
208 return error;
209 }
210
Jamie Madille6b6da02014-10-02 11:03:14 -0400211 error = commitRegion(index, region);
212 if (error.isError())
213 {
214 return error;
215 }
216
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700217 mDirtyImages = true;
218 }
219
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400220 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700221}
222
Geoff Langb5348332014-09-02 13:16:34 -0400223gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700224{
225 if (pixels != NULL)
226 {
Geoff Langb5348332014-09-02 13:16:34 -0400227 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixels);
228 if (error.isError())
229 {
230 return error;
231 }
232
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700233 mDirtyImages = true;
234 }
Geoff Langb5348332014-09-02 13:16:34 -0400235
236 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700237}
238
Geoff Langb5348332014-09-02 13:16:34 -0400239gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Brandon Jones78b1acd2014-07-15 15:33:07 -0700240 GLenum format, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700241{
242 if (pixels != NULL)
243 {
Geoff Langb5348332014-09-02 13:16:34 -0400244 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixels);
245 if (error.isError())
246 {
247 return error;
248 }
249
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700250 mDirtyImages = true;
251 }
252
Geoff Langb5348332014-09-02 13:16:34 -0400253 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700254}
255
256bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
257{
258 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
259}
260
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400261gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
262 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700263{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400264 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700265 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
266 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400267 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700268 }
269
270 // In order to perform the fast copy through the shader, we must have the right format, and be able
271 // to create a render target.
272 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
273
Jacek Cabana5521de2014-10-01 17:23:46 +0200274 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700275
Geoff Langae5122c2014-08-27 14:08:43 -0400276 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
277 if (error.isError())
278 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400279 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400280 }
281
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400282 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700283}
284
285GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
286{
287 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
288 {
289 // Maximum number of levels
290 return gl::log2(std::max(std::max(width, height), depth)) + 1;
291 }
292 else
293 {
294 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
295 return 1;
296 }
297}
298
299int TextureD3D::mipLevels() const
300{
301 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
302}
303
Jamie Madill98553e32014-09-30 16:33:50 -0400304TextureStorage *TextureD3D::getStorage()
305{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400306 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400307 return mTexStorage;
308}
309
Jamie Madill3269bcb2014-09-30 16:33:52 -0400310Image *TextureD3D::getBaseLevelImage() const
311{
312 return getImage(getImageIndex(0, 0));
313}
314
Jamie Madill4aa79e12014-09-29 10:46:14 -0400315void TextureD3D::generateMipmaps()
316{
Jamie Madill9aca0592014-10-06 16:26:59 -0400317 GLint mipCount = mipLevels();
318
319 if (mipCount == 1)
320 {
321 return; // no-op
322 }
323
324 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400325 initMipmapsImages();
326
327 // We know that all layers have the same dimension, for the texture to be complete
328 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400329
Jamie Madill9aca0592014-10-06 16:26:59 -0400330 // When making mipmaps with the setData workaround enabled, the texture storage has
331 // the image data already. For non-render-target storage, we have to pull it out into
332 // an image layer.
333 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
334 {
335 if (!mTexStorage->isRenderTarget())
336 {
337 // Copy from the storage mip 0 to Image mip 0
338 for (GLint layer = 0; layer < layerCount; ++layer)
339 {
340 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400341
Jamie Madill9aca0592014-10-06 16:26:59 -0400342 Image *image = getImage(srcIndex);
343 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
344 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
345 }
346 }
347 else
348 {
349 updateStorage();
350 }
351 }
352
353 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400354
355 for (GLint layer = 0; layer < layerCount; ++layer)
356 {
357 for (GLint mip = 1; mip < mipCount; ++mip)
358 {
359 ASSERT(getLayerCount(mip) == layerCount);
360
361 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
362 gl::ImageIndex destIndex = getImageIndex(mip, layer);
363
364 if (renderableStorage)
365 {
366 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400367 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400368 }
369 else
370 {
371 // CPU-side mipmapping
372 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
373 }
374 }
375 }
376}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700377
Jamie Madill135570a2014-09-30 16:33:51 -0400378bool TextureD3D::isBaseImageZeroSize() const
379{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400380 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400381
382 if (!baseImage || baseImage->getWidth() <= 0)
383 {
384 return true;
385 }
386
387 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
388 {
389 return true;
390 }
391
392 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
393 {
394 return true;
395 }
396
397 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
398 {
399 return true;
400 }
401
402 return false;
403}
404
Geoff Langef7b0162014-09-04 13:29:23 -0400405gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400406{
Geoff Langef7b0162014-09-04 13:29:23 -0400407 gl::Error error = initializeStorage(true);
408 if (error.isError())
409 {
410 return error;
411 }
Jamie Madill135570a2014-09-30 16:33:51 -0400412
413 if (!isBaseImageZeroSize())
414 {
415 ASSERT(mTexStorage);
416 if (!mTexStorage->isRenderTarget())
417 {
Geoff Langef7b0162014-09-04 13:29:23 -0400418 TextureStorage *newRenderTargetStorage = NULL;
419 error = createCompleteStorage(true, &newRenderTargetStorage);
420 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400421 {
Geoff Langef7b0162014-09-04 13:29:23 -0400422 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400423 }
424
Geoff Langef7b0162014-09-04 13:29:23 -0400425 error = mTexStorage->copyToStorage(newRenderTargetStorage);
426 if (error.isError())
427 {
428 SafeDelete(newRenderTargetStorage);
429 return error;
430 }
431
432 error = setCompleteTexStorage(newRenderTargetStorage);
433 if (error.isError())
434 {
435 SafeDelete(newRenderTargetStorage);
436 return error;
437 }
Jamie Madill135570a2014-09-30 16:33:51 -0400438 }
439 }
440
Geoff Langef7b0162014-09-04 13:29:23 -0400441 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400442}
443
Jamie Madille76bdda2014-10-20 17:13:52 -0400444bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
445{
446 rx::Image *image = getImage(index);
447 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
448 return (image->isRenderableFormat() && levelsComplete);
449}
450
Jamie Madill710e5772014-10-20 17:13:53 -0400451gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
452{
453 if (mTexStorage)
454 {
455 ASSERT(isValidIndex(index));
456 Image *image = getImage(index);
457 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
458 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
459 if (error.isError())
460 {
461 return error;
462 }
463
464 image->markClean();
465 }
466
467 return gl::Error(GL_NO_ERROR);
468}
469
Brandon Jones78b1acd2014-07-15 15:33:07 -0700470TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400471 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700472{
473 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
474 {
475 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
476 }
477}
478
479TextureD3D_2D::~TextureD3D_2D()
480{
Austin Kinross69822602014-08-12 15:51:37 -0700481 // Delete the Images before the TextureStorage.
482 // Images might be relying on the TextureStorage for some of their data.
483 // 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 -0700484 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
485 {
486 delete mImageArray[i];
487 }
Austin Kinross69822602014-08-12 15:51:37 -0700488
489 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700490}
491
Brandon Jonescef06ff2014-08-05 13:27:48 -0700492Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700493{
494 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700495 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700496 return mImageArray[level];
497}
498
Jamie Madillfeda4d22014-09-17 13:03:29 -0400499Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
500{
501 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400502 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400503 ASSERT(index.type == GL_TEXTURE_2D);
504 return mImageArray[index.mipIndex];
505}
506
Brandon Jonescef06ff2014-08-05 13:27:48 -0700507GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700508{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700509 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
510 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700511}
512
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700513GLsizei TextureD3D_2D::getWidth(GLint level) const
514{
515 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
516 return mImageArray[level]->getWidth();
517 else
518 return 0;
519}
520
521GLsizei TextureD3D_2D::getHeight(GLint level) const
522{
523 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
524 return mImageArray[level]->getHeight();
525 else
526 return 0;
527}
528
529GLenum TextureD3D_2D::getInternalFormat(GLint level) const
530{
531 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
532 return mImageArray[level]->getInternalFormat();
533 else
534 return GL_NONE;
535}
536
537GLenum TextureD3D_2D::getActualFormat(GLint level) const
538{
539 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
540 return mImageArray[level]->getActualFormat();
541 else
542 return GL_NONE;
543}
544
545bool TextureD3D_2D::isDepth(GLint level) const
546{
Geoff Lang5d601382014-07-22 15:14:06 -0400547 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700548}
549
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400550gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
551 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
552 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700553{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700554 ASSERT(target == GL_TEXTURE_2D && depth == 1);
555
Geoff Lang5d601382014-07-22 15:14:06 -0400556 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
557
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558 bool fastUnpacked = false;
559
Brandon Jonescef06ff2014-08-05 13:27:48 -0700560 redefineImage(level, sizedInternalFormat, width, height);
561
Jamie Madillba6bc952014-10-06 10:56:22 -0400562 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
563
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700564 // Attempt a fast gpu copy of the pixel data to the surface
565 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
566 {
567 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400568 RenderTarget *destRenderTarget = NULL;
569 gl::Error error = getRenderTarget(index, &destRenderTarget);
570 if (error.isError())
571 {
572 return error;
573 }
574
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700575 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
576
Geoff Lang64f23f62014-09-10 14:40:12 -0400577 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
578 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700579 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400580 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700581 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400582
583 // Ensure we don't overwrite our newly initialized data
584 mImageArray[level]->markClean();
585
586 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587 }
588
589 if (!fastUnpacked)
590 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400591 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400592 if (error.isError())
593 {
594 return error;
595 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700596 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400597
598 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599}
600
Geoff Langb5348332014-09-02 13:16:34 -0400601gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
602 GLsizei width, GLsizei height, GLsizei depth,
603 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700605 ASSERT(target == GL_TEXTURE_2D && depth == 1);
606
607 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
608 redefineImage(level, format, width, height);
609
Geoff Langb5348332014-09-02 13:16:34 -0400610 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700611}
612
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400613gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
614 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
615 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700617 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
618
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 bool fastUnpacked = false;
620
Jamie Madillac7579c2014-09-17 16:59:33 -0400621 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400622 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700623 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
624 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400625 RenderTarget *renderTarget = NULL;
626 gl::Error error = getRenderTarget(index, &renderTarget);
627 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700628 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400629 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700630 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400631
632 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
633 if (error.isError())
634 {
635 return error;
636 }
637
638 // Ensure we don't overwrite our newly initialized data
639 mImageArray[level]->markClean();
640
641 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700642 }
643
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400644 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700645 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400646 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
647 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700648 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400649
650 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700651}
652
Geoff Langb5348332014-09-02 13:16:34 -0400653gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
654 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
655 GLsizei imageSize, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700656{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700657 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
658
Geoff Langb5348332014-09-02 13:16:34 -0400659 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
660 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700661 {
Geoff Langb5348332014-09-02 13:16:34 -0400662 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663 }
Geoff Langb5348332014-09-02 13:16:34 -0400664
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400665 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
666 gl::Box region(xoffset, yoffset, 0, width, height, 1);
667 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700668}
669
Geoff Langef7b0162014-09-04 13:29:23 -0400670gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
671 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700673 ASSERT(target == GL_TEXTURE_2D);
674
675 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
676 redefineImage(level, sizedInternalFormat, width, height);
677
Jamie Madill82bf0c52014-10-03 11:50:53 -0400678 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400679 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400680
Jamie Madille76bdda2014-10-20 17:13:52 -0400681 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700682 {
Geoff Langef7b0162014-09-04 13:29:23 -0400683 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
684 if (error.isError())
685 {
686 return error;
687 }
688
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700689 mDirtyImages = true;
690 }
691 else
692 {
Geoff Langef7b0162014-09-04 13:29:23 -0400693 gl::Error error = ensureRenderTarget();
694 if (error.isError())
695 {
696 return error;
697 }
698
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700699 mImageArray[level]->markClean();
700
701 if (width != 0 && height != 0 && isValidLevel(level))
702 {
Geoff Langef7b0162014-09-04 13:29:23 -0400703 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
704 if (error.isError())
705 {
706 return error;
707 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700708 }
709 }
Geoff Langef7b0162014-09-04 13:29:23 -0400710
711 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712}
713
Geoff Langef7b0162014-09-04 13:29:23 -0400714gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
715 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700716{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700717 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
718
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700719 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
720 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700721
Jamie Madill82bf0c52014-10-03 11:50:53 -0400722 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400723 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400724
Jamie Madille76bdda2014-10-20 17:13:52 -0400725 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700726 {
Geoff Langef7b0162014-09-04 13:29:23 -0400727 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
728 if (error.isError())
729 {
730 return error;
731 }
732
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733 mDirtyImages = true;
734 }
735 else
736 {
Geoff Langef7b0162014-09-04 13:29:23 -0400737 gl::Error error = ensureRenderTarget();
738 if (error.isError())
739 {
740 return error;
741 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700742
743 if (isValidLevel(level))
744 {
Geoff Langef7b0162014-09-04 13:29:23 -0400745 error = updateStorageLevel(level);
746 if (error.isError())
747 {
748 return error;
749 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700750
Geoff Langef7b0162014-09-04 13:29:23 -0400751 error = mRenderer->copyImage2D(source, sourceRect,
752 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
753 xoffset, yoffset, mTexStorage, level);
754 if (error.isError())
755 {
756 return error;
757 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700758 }
759 }
Geoff Langef7b0162014-09-04 13:29:23 -0400760
761 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700762}
763
Geoff Lang1f8532b2014-09-05 09:46:13 -0400764gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700766 ASSERT(target == GL_TEXTURE_2D && depth == 1);
767
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700768 for (int level = 0; level < levels; level++)
769 {
770 GLsizei levelWidth = std::max(1, width >> level);
771 GLsizei levelHeight = std::max(1, height >> level);
772 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
773 }
774
775 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
776 {
777 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
778 }
779
Geoff Lang1f8532b2014-09-05 09:46:13 -0400780 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400781 bool renderTarget = IsRenderTargetUsage(mUsage);
782 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400783
784 gl::Error error = setCompleteTexStorage(storage);
785 if (error.isError())
786 {
787 SafeDelete(storage);
788 return error;
789 }
790
791 mImmutable = true;
792
793 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700794}
795
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700796void TextureD3D_2D::bindTexImage(egl::Surface *surface)
797{
798 GLenum internalformat = surface->getFormat();
799
800 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
801
802 if (mTexStorage)
803 {
804 SafeDelete(mTexStorage);
805 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400806
807 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700808
809 mDirtyImages = true;
810}
811
812void TextureD3D_2D::releaseTexImage()
813{
814 if (mTexStorage)
815 {
816 SafeDelete(mTexStorage);
817 }
818
819 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
820 {
821 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
822 }
823}
824
Jamie Madill4aa79e12014-09-29 10:46:14 -0400825void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700826{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700827 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700828 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700829 for (int level = 1; level < levelCount; level++)
830 {
831 redefineImage(level, getBaseLevelInternalFormat(),
832 std::max(getBaseLevelWidth() >> level, 1),
833 std::max(getBaseLevelHeight() >> level, 1));
834 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700835}
836
Jamie Madillac7579c2014-09-17 16:59:33 -0400837unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700838{
Jamie Madillac7579c2014-09-17 16:59:33 -0400839 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400840 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700841}
842
Geoff Lang64f23f62014-09-10 14:40:12 -0400843gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700844{
Jamie Madillac7579c2014-09-17 16:59:33 -0400845 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700846
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700847 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400848 gl::Error error = ensureRenderTarget();
849 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700850 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400851 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700852 }
853
Geoff Langef7b0162014-09-04 13:29:23 -0400854 error = updateStorageLevel(index.mipIndex);
855 if (error.isError())
856 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400857 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400858 }
859
Geoff Lang64f23f62014-09-10 14:40:12 -0400860 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700861}
862
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863bool TextureD3D_2D::isValidLevel(int level) const
864{
865 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
866}
867
868bool TextureD3D_2D::isLevelComplete(int level) const
869{
870 if (isImmutable())
871 {
872 return true;
873 }
874
Brandon Jones78b1acd2014-07-15 15:33:07 -0700875 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700876
877 GLsizei width = baseImage->getWidth();
878 GLsizei height = baseImage->getHeight();
879
880 if (width <= 0 || height <= 0)
881 {
882 return false;
883 }
884
885 // The base image level is complete if the width and height are positive
886 if (level == 0)
887 {
888 return true;
889 }
890
891 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700892 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700893
894 if (image->getInternalFormat() != baseImage->getInternalFormat())
895 {
896 return false;
897 }
898
899 if (image->getWidth() != std::max(1, width >> level))
900 {
901 return false;
902 }
903
904 if (image->getHeight() != std::max(1, height >> level))
905 {
906 return false;
907 }
908
909 return true;
910}
911
Jamie Madille76bdda2014-10-20 17:13:52 -0400912bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
913{
914 return isLevelComplete(index.mipIndex);
915}
916
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700917// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400918gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700919{
920 // Only initialize the first time this texture is used as a render target or shader resource
921 if (mTexStorage)
922 {
Geoff Langef7b0162014-09-04 13:29:23 -0400923 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700924 }
925
926 // do not attempt to create storage for nonexistant data
927 if (!isLevelComplete(0))
928 {
Geoff Langef7b0162014-09-04 13:29:23 -0400929 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700930 }
931
932 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
933
Geoff Langef7b0162014-09-04 13:29:23 -0400934 TextureStorage *storage = NULL;
935 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
936 if (error.isError())
937 {
938 return error;
939 }
940
941 error = setCompleteTexStorage(storage);
942 if (error.isError())
943 {
944 SafeDelete(storage);
945 return error;
946 }
947
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700948 ASSERT(mTexStorage);
949
950 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400951 error = updateStorage();
952 if (error.isError())
953 {
954 return error;
955 }
956
957 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700958}
959
Geoff Langef7b0162014-09-04 13:29:23 -0400960gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700961{
962 GLsizei width = getBaseLevelWidth();
963 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400964 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700965
966 ASSERT(width > 0 && height > 0);
967
968 // use existing storage level count, when previously specified by TexStorage*D
969 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
970
Geoff Langef7b0162014-09-04 13:29:23 -0400971 // TODO(geofflang): Determine if the texture creation succeeded
972 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
973
974 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700975}
976
Geoff Langef7b0162014-09-04 13:29:23 -0400977gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700978{
Geoff Langef7b0162014-09-04 13:29:23 -0400979 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700980 {
Geoff Langef7b0162014-09-04 13:29:23 -0400981 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700982 {
Geoff Langef7b0162014-09-04 13:29:23 -0400983 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
984 if (error.isError())
985 {
986 return error;
987 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700988 }
989 }
990
Geoff Langef7b0162014-09-04 13:29:23 -0400991 SafeDelete(mTexStorage);
992 mTexStorage = newCompleteTexStorage;
993
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700994 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -0400995
996 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700997}
998
Geoff Langef7b0162014-09-04 13:29:23 -0400999gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001000{
1001 ASSERT(mTexStorage != NULL);
1002 GLint storageLevels = mTexStorage->getLevelCount();
1003 for (int level = 0; level < storageLevels; level++)
1004 {
1005 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1006 {
Geoff Langef7b0162014-09-04 13:29:23 -04001007 gl::Error error = updateStorageLevel(level);
1008 if (error.isError())
1009 {
1010 return error;
1011 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001012 }
1013 }
Geoff Langef7b0162014-09-04 13:29:23 -04001014
1015 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001016}
1017
Geoff Langef7b0162014-09-04 13:29:23 -04001018gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001019{
1020 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1021 ASSERT(isLevelComplete(level));
1022
1023 if (mImageArray[level]->isDirty())
1024 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001025 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1026 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001027 gl::Error error = commitRegion(index, region);
1028 if (error.isError())
1029 {
1030 return error;
1031 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001032 }
Geoff Langef7b0162014-09-04 13:29:23 -04001033
1034 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001035}
1036
1037void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1038{
1039 // If there currently is a corresponding storage texture image, it has these parameters
1040 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1041 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1042 const GLenum storageFormat = getBaseLevelInternalFormat();
1043
1044 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1045
1046 if (mTexStorage)
1047 {
1048 const int storageLevels = mTexStorage->getLevelCount();
1049
1050 if ((level >= storageLevels && storageLevels != 0) ||
1051 width != storageWidth ||
1052 height != storageHeight ||
1053 internalformat != storageFormat) // Discard mismatched storage
1054 {
1055 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1056 {
1057 mImageArray[i]->markDirty();
1058 }
1059
1060 SafeDelete(mTexStorage);
1061 mDirtyImages = true;
1062 }
1063 }
1064}
1065
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001066gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1067{
1068 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1069}
Brandon Jones0511e802014-07-14 16:27:26 -07001070
Jamie Madillcb83dc12014-09-29 10:46:12 -04001071gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1072{
1073 // "layer" does not apply to 2D Textures.
1074 return gl::ImageIndex::Make2D(mip);
1075}
1076
Jamie Madill710e5772014-10-20 17:13:53 -04001077bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1078{
1079 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1080 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1081}
1082
Brandon Jones78b1acd2014-07-15 15:33:07 -07001083TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001084 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001085{
1086 for (int i = 0; i < 6; i++)
1087 {
1088 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1089 {
1090 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1091 }
1092 }
1093}
1094
1095TextureD3D_Cube::~TextureD3D_Cube()
1096{
Austin Kinross69822602014-08-12 15:51:37 -07001097 // Delete the Images before the TextureStorage.
1098 // Images might be relying on the TextureStorage for some of their data.
1099 // 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 -07001100 for (int i = 0; i < 6; i++)
1101 {
1102 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1103 {
1104 SafeDelete(mImageArray[i][j]);
1105 }
1106 }
Austin Kinross69822602014-08-12 15:51:37 -07001107
1108 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001109}
1110
Brandon Jonescef06ff2014-08-05 13:27:48 -07001111Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001112{
1113 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001114 ASSERT(layer < 6);
1115 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001116}
1117
Jamie Madillfeda4d22014-09-17 13:03:29 -04001118Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1119{
1120 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1121 ASSERT(index.layerIndex < 6);
1122 return mImageArray[index.layerIndex][index.mipIndex];
1123}
1124
Brandon Jonescef06ff2014-08-05 13:27:48 -07001125GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001126{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001127 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1128 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001129}
1130
Brandon Jonescef06ff2014-08-05 13:27:48 -07001131GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001132{
1133 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001134 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001135 else
1136 return GL_NONE;
1137}
1138
Brandon Jonescef06ff2014-08-05 13:27:48 -07001139bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001140{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001141 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001142}
1143
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001144gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1145 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1146 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001147{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001148 ASSERT(depth == 1);
1149
Geoff Lang5d601382014-07-22 15:14:06 -04001150 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001151 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001152
Jamie Madillba6bc952014-10-06 10:56:22 -04001153 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001154
Jamie Madillba6bc952014-10-06 10:56:22 -04001155 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001156}
1157
Geoff Langb5348332014-09-02 13:16:34 -04001158gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1159 GLsizei width, GLsizei height, GLsizei depth,
1160 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001161{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001162 ASSERT(depth == 1);
1163
Brandon Jones0511e802014-07-14 16:27:26 -07001164 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001165 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1166
Brandon Jones0511e802014-07-14 16:27:26 -07001167 redefineImage(faceIndex, level, format, width, height);
1168
Geoff Langb5348332014-09-02 13:16:34 -04001169 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001170}
1171
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001172gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1173 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1174 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001175{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001176 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001177 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001178 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001179}
1180
Geoff Langb5348332014-09-02 13:16:34 -04001181gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1182 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1183 GLsizei imageSize, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001185 ASSERT(depth == 1 && zoffset == 0);
1186
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001187 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001188
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001189 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 -04001190 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001191 {
Geoff Langb5348332014-09-02 13:16:34 -04001192 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001193 }
Geoff Langb5348332014-09-02 13:16:34 -04001194
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001195 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1196 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001197}
1198
Geoff Langef7b0162014-09-04 13:29:23 -04001199gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1200 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001201{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001202 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001203 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1204
Brandon Jones0511e802014-07-14 16:27:26 -07001205 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1206
Jamie Madill82bf0c52014-10-03 11:50:53 -04001207 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001208 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001209
Jamie Madille76bdda2014-10-20 17:13:52 -04001210 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001211 {
Geoff Langef7b0162014-09-04 13:29:23 -04001212 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1213 if (error.isError())
1214 {
1215 return error;
1216 }
1217
Brandon Jones0511e802014-07-14 16:27:26 -07001218 mDirtyImages = true;
1219 }
1220 else
1221 {
Geoff Langef7b0162014-09-04 13:29:23 -04001222 gl::Error error = ensureRenderTarget();
1223 if (error.isError())
1224 {
1225 return error;
1226 }
1227
Brandon Jones0511e802014-07-14 16:27:26 -07001228 mImageArray[faceIndex][level]->markClean();
1229
1230 ASSERT(width == height);
1231
1232 if (width > 0 && isValidFaceLevel(faceIndex, level))
1233 {
Geoff Langef7b0162014-09-04 13:29:23 -04001234 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1235 if (error.isError())
1236 {
1237 return error;
1238 }
Brandon Jones0511e802014-07-14 16:27:26 -07001239 }
1240 }
Geoff Langef7b0162014-09-04 13:29:23 -04001241
1242 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001243}
1244
Geoff Langef7b0162014-09-04 13:29:23 -04001245gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1246 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001247{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001248 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001249
Jamie Madill82bf0c52014-10-03 11:50:53 -04001250 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001251 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001252
Jamie Madille76bdda2014-10-20 17:13:52 -04001253 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001254 {
Geoff Langef7b0162014-09-04 13:29:23 -04001255 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1256 if (error.isError())
1257 {
1258 return error;
1259 }
1260
Brandon Jones0511e802014-07-14 16:27:26 -07001261 mDirtyImages = true;
1262 }
1263 else
1264 {
Geoff Langef7b0162014-09-04 13:29:23 -04001265 gl::Error error = ensureRenderTarget();
1266 if (error.isError())
1267 {
1268 return error;
1269 }
Brandon Jones0511e802014-07-14 16:27:26 -07001270
1271 if (isValidFaceLevel(faceIndex, level))
1272 {
Geoff Langef7b0162014-09-04 13:29:23 -04001273 error = updateStorageFaceLevel(faceIndex, level);
1274 if (error.isError())
1275 {
1276 return error;
1277 }
Brandon Jones0511e802014-07-14 16:27:26 -07001278
Geoff Langef7b0162014-09-04 13:29:23 -04001279 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1280 xoffset, yoffset, mTexStorage, target, level);
1281 if (error.isError())
1282 {
1283 return error;
1284 }
Brandon Jones0511e802014-07-14 16:27:26 -07001285 }
1286 }
Geoff Langef7b0162014-09-04 13:29:23 -04001287
1288 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001289}
1290
Geoff Lang1f8532b2014-09-05 09:46:13 -04001291gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001292{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001293 ASSERT(width == height);
1294 ASSERT(depth == 1);
1295
Brandon Jones0511e802014-07-14 16:27:26 -07001296 for (int level = 0; level < levels; level++)
1297 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001298 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001299 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1300 {
1301 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1302 }
1303 }
1304
1305 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1306 {
1307 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1308 {
1309 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1310 }
1311 }
1312
Geoff Lang1f8532b2014-09-05 09:46:13 -04001313 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001314 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001315 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001316
1317 gl::Error error = setCompleteTexStorage(storage);
1318 if (error.isError())
1319 {
1320 SafeDelete(storage);
1321 return error;
1322 }
1323
1324 mImmutable = true;
1325
1326 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001327}
1328
Brandon Jones0511e802014-07-14 16:27:26 -07001329// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1330bool TextureD3D_Cube::isCubeComplete() const
1331{
1332 int baseWidth = getBaseLevelWidth();
1333 int baseHeight = getBaseLevelHeight();
1334 GLenum baseFormat = getBaseLevelInternalFormat();
1335
1336 if (baseWidth <= 0 || baseWidth != baseHeight)
1337 {
1338 return false;
1339 }
1340
1341 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1342 {
1343 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1344
1345 if (faceBaseImage.getWidth() != baseWidth ||
1346 faceBaseImage.getHeight() != baseHeight ||
1347 faceBaseImage.getInternalFormat() != baseFormat )
1348 {
1349 return false;
1350 }
1351 }
1352
1353 return true;
1354}
1355
Brandon Jones6053a522014-07-25 16:22:09 -07001356void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1357{
1358 UNREACHABLE();
1359}
1360
1361void TextureD3D_Cube::releaseTexImage()
1362{
1363 UNREACHABLE();
1364}
1365
1366
Jamie Madill4aa79e12014-09-29 10:46:14 -04001367void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001368{
1369 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1370 int levelCount = mipLevels();
1371 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1372 {
1373 for (int level = 1; level < levelCount; level++)
1374 {
1375 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1376 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1377 }
1378 }
Brandon Jones0511e802014-07-14 16:27:26 -07001379}
1380
Jamie Madillac7579c2014-09-17 16:59:33 -04001381unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001382{
Geoff Langef7b0162014-09-04 13:29:23 -04001383 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001384}
1385
Geoff Lang64f23f62014-09-10 14:40:12 -04001386gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001387{
Jamie Madillac7579c2014-09-17 16:59:33 -04001388 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001389
1390 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001391 gl::Error error = ensureRenderTarget();
1392 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001393 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001394 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001395 }
1396
Geoff Langef7b0162014-09-04 13:29:23 -04001397 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1398 if (error.isError())
1399 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001400 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001401 }
1402
Geoff Lang64f23f62014-09-10 14:40:12 -04001403 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001404}
1405
Geoff Langef7b0162014-09-04 13:29:23 -04001406gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001407{
1408 // Only initialize the first time this texture is used as a render target or shader resource
1409 if (mTexStorage)
1410 {
Geoff Langef7b0162014-09-04 13:29:23 -04001411 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001412 }
1413
1414 // do not attempt to create storage for nonexistant data
1415 if (!isFaceLevelComplete(0, 0))
1416 {
Geoff Langef7b0162014-09-04 13:29:23 -04001417 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001418 }
1419
1420 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1421
Geoff Langef7b0162014-09-04 13:29:23 -04001422 TextureStorage *storage = NULL;
1423 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1424 if (error.isError())
1425 {
1426 return error;
1427 }
1428
1429 error = setCompleteTexStorage(storage);
1430 if (error.isError())
1431 {
1432 SafeDelete(storage);
1433 return error;
1434 }
1435
Brandon Jones0511e802014-07-14 16:27:26 -07001436 ASSERT(mTexStorage);
1437
1438 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001439 error = updateStorage();
1440 if (error.isError())
1441 {
1442 return error;
1443 }
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::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001449{
1450 GLsizei size = getBaseLevelWidth();
1451
1452 ASSERT(size > 0);
1453
1454 // use existing storage level count, when previously specified by TexStorage*D
1455 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1456
Geoff Langef7b0162014-09-04 13:29:23 -04001457 // TODO (geofflang): detect if storage creation succeeded
1458 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1459
1460 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001461}
1462
Geoff Langef7b0162014-09-04 13:29:23 -04001463gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001464{
Geoff Langef7b0162014-09-04 13:29:23 -04001465 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001466 {
1467 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1468 {
Geoff Langef7b0162014-09-04 13:29:23 -04001469 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001470 {
Geoff Langef7b0162014-09-04 13:29:23 -04001471 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1472 if (error.isError())
1473 {
1474 return error;
1475 }
Brandon Jones0511e802014-07-14 16:27:26 -07001476 }
1477 }
1478 }
1479
Geoff Langef7b0162014-09-04 13:29:23 -04001480 SafeDelete(mTexStorage);
1481 mTexStorage = newCompleteTexStorage;
1482
Brandon Jones0511e802014-07-14 16:27:26 -07001483 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001484 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001485}
1486
Geoff Langef7b0162014-09-04 13:29:23 -04001487gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001488{
1489 ASSERT(mTexStorage != NULL);
1490 GLint storageLevels = mTexStorage->getLevelCount();
1491 for (int face = 0; face < 6; face++)
1492 {
1493 for (int level = 0; level < storageLevels; level++)
1494 {
1495 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1496 {
Geoff Langef7b0162014-09-04 13:29:23 -04001497 gl::Error error = updateStorageFaceLevel(face, level);
1498 if (error.isError())
1499 {
1500 return error;
1501 }
Brandon Jones0511e802014-07-14 16:27:26 -07001502 }
1503 }
1504 }
Geoff Langef7b0162014-09-04 13:29:23 -04001505
1506 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001507}
1508
Brandon Jones0511e802014-07-14 16:27:26 -07001509bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1510{
1511 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1512}
1513
Brandon Jones0511e802014-07-14 16:27:26 -07001514bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1515{
1516 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1517
1518 if (isImmutable())
1519 {
1520 return true;
1521 }
1522
1523 int baseSize = getBaseLevelWidth();
1524
1525 if (baseSize <= 0)
1526 {
1527 return false;
1528 }
1529
1530 // "isCubeComplete" checks for base level completeness and we must call that
1531 // to determine if any face at level 0 is complete. We omit that check here
1532 // to avoid re-checking cube-completeness for every face at level 0.
1533 if (level == 0)
1534 {
1535 return true;
1536 }
1537
1538 // Check that non-zero levels are consistent with the base level.
1539 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1540
1541 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1542 {
1543 return false;
1544 }
1545
1546 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1547 {
1548 return false;
1549 }
1550
1551 return true;
1552}
1553
Jamie Madille76bdda2014-10-20 17:13:52 -04001554bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1555{
1556 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1557}
1558
Geoff Langef7b0162014-09-04 13:29:23 -04001559gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001560{
1561 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1562 ImageD3D *image = mImageArray[faceIndex][level];
1563
1564 if (image->isDirty())
1565 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001566 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1567 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1568 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001569 gl::Error error = commitRegion(index, region);
1570 if (error.isError())
1571 {
1572 return error;
1573 }
Brandon Jones0511e802014-07-14 16:27:26 -07001574 }
Geoff Langef7b0162014-09-04 13:29:23 -04001575
1576 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001577}
1578
1579void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1580{
1581 // If there currently is a corresponding storage texture image, it has these parameters
1582 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1583 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1584 const GLenum storageFormat = getBaseLevelInternalFormat();
1585
1586 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1587
1588 if (mTexStorage)
1589 {
1590 const int storageLevels = mTexStorage->getLevelCount();
1591
1592 if ((level >= storageLevels && storageLevels != 0) ||
1593 width != storageWidth ||
1594 height != storageHeight ||
1595 internalformat != storageFormat) // Discard mismatched storage
1596 {
1597 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1598 {
1599 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1600 {
1601 mImageArray[faceIndex][level]->markDirty();
1602 }
1603 }
1604
1605 SafeDelete(mTexStorage);
1606
1607 mDirtyImages = true;
1608 }
1609 }
1610}
1611
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001612gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1613{
1614 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1615}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001616
Jamie Madillcb83dc12014-09-29 10:46:12 -04001617gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1618{
1619 // The "layer" of the image index corresponds to the cube face
1620 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1621}
1622
Jamie Madill710e5772014-10-20 17:13:53 -04001623bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1624{
1625 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1626 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1627}
1628
Brandon Jones78b1acd2014-07-15 15:33:07 -07001629TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001630 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001631{
1632 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1633 {
1634 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1635 }
1636}
1637
1638TextureD3D_3D::~TextureD3D_3D()
1639{
Austin Kinross69822602014-08-12 15:51:37 -07001640 // Delete the Images before the TextureStorage.
1641 // Images might be relying on the TextureStorage for some of their data.
1642 // 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 -07001643 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1644 {
1645 delete mImageArray[i];
1646 }
Austin Kinross69822602014-08-12 15:51:37 -07001647
1648 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001649}
1650
Brandon Jonescef06ff2014-08-05 13:27:48 -07001651Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001652{
1653 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001654 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001655 return mImageArray[level];
1656}
1657
Jamie Madillfeda4d22014-09-17 13:03:29 -04001658Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1659{
1660 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001661 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001662 ASSERT(index.type == GL_TEXTURE_3D);
1663 return mImageArray[index.mipIndex];
1664}
1665
Brandon Jonescef06ff2014-08-05 13:27:48 -07001666GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001667{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001668 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1669 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001670}
1671
Brandon Jones78b1acd2014-07-15 15:33:07 -07001672GLsizei TextureD3D_3D::getWidth(GLint level) const
1673{
1674 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1675 return mImageArray[level]->getWidth();
1676 else
1677 return 0;
1678}
1679
1680GLsizei TextureD3D_3D::getHeight(GLint level) const
1681{
1682 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1683 return mImageArray[level]->getHeight();
1684 else
1685 return 0;
1686}
1687
1688GLsizei TextureD3D_3D::getDepth(GLint level) const
1689{
1690 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1691 return mImageArray[level]->getDepth();
1692 else
1693 return 0;
1694}
1695
1696GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1697{
1698 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1699 return mImageArray[level]->getInternalFormat();
1700 else
1701 return GL_NONE;
1702}
1703
1704bool TextureD3D_3D::isDepth(GLint level) const
1705{
Geoff Lang5d601382014-07-22 15:14:06 -04001706 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001707}
1708
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001709gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1710 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1711 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001712{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001713 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001714 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1715
Brandon Jones78b1acd2014-07-15 15:33:07 -07001716 redefineImage(level, sizedInternalFormat, width, height, depth);
1717
1718 bool fastUnpacked = false;
1719
Jamie Madillba6bc952014-10-06 10:56:22 -04001720 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1721
Brandon Jones78b1acd2014-07-15 15:33:07 -07001722 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1723 if (isFastUnpackable(unpack, sizedInternalFormat))
1724 {
1725 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001726 RenderTarget *destRenderTarget = NULL;
1727 gl::Error error = getRenderTarget(index, &destRenderTarget);
1728 if (error.isError())
1729 {
1730 return error;
1731 }
1732
Brandon Jones78b1acd2014-07-15 15:33:07 -07001733 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1734
Geoff Lang64f23f62014-09-10 14:40:12 -04001735 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1736 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001738 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001739 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001740
1741 // Ensure we don't overwrite our newly initialized data
1742 mImageArray[level]->markClean();
1743
1744 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001745 }
1746
1747 if (!fastUnpacked)
1748 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001749 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001750 if (error.isError())
1751 {
1752 return error;
1753 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001754 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001755
1756 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001757}
1758
Geoff Langb5348332014-09-02 13:16:34 -04001759gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1760 GLsizei width, GLsizei height,GLsizei depth,
1761 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001763 ASSERT(target == GL_TEXTURE_3D);
1764
Brandon Jones78b1acd2014-07-15 15:33:07 -07001765 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1766 redefineImage(level, format, width, height, depth);
1767
Geoff Langb5348332014-09-02 13:16:34 -04001768 return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001769}
1770
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001771gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1772 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1773 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001774{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001775 ASSERT(target == GL_TEXTURE_3D);
1776
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777 bool fastUnpacked = false;
1778
Jamie Madillac7579c2014-09-17 16:59:33 -04001779 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1780
Brandon Jones78b1acd2014-07-15 15:33:07 -07001781 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1782 if (isFastUnpackable(unpack, getInternalFormat(level)))
1783 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001784 RenderTarget *destRenderTarget = NULL;
1785 gl::Error error = getRenderTarget(index, &destRenderTarget);
1786 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001787 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001788 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001789 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001790
1791 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1792 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1793 if (error.isError())
1794 {
1795 return error;
1796 }
1797
1798 // Ensure we don't overwrite our newly initialized data
1799 mImageArray[level]->markClean();
1800
1801 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802 }
1803
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001804 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001805 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001806 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1807 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001808 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001809
1810 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001811}
1812
Geoff Langb5348332014-09-02 13:16:34 -04001813gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1814 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
1815 GLsizei imageSize, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001816{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001817 ASSERT(target == GL_TEXTURE_3D);
1818
Geoff Langb5348332014-09-02 13:16:34 -04001819 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
1820 format, imageSize, pixels, mImageArray[level]);
1821 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001822 {
Geoff Langb5348332014-09-02 13:16:34 -04001823 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 }
Geoff Langb5348332014-09-02 13:16:34 -04001825
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001826 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1827 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1828 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001829}
1830
Geoff Langef7b0162014-09-04 13:29:23 -04001831gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1832 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001833{
1834 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001835 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001836}
1837
Geoff Langef7b0162014-09-04 13:29:23 -04001838gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1839 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001840{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001841 ASSERT(target == GL_TEXTURE_3D);
1842
Jamie Madill82bf0c52014-10-03 11:50:53 -04001843 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001844 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001845
Jamie Madille76bdda2014-10-20 17:13:52 -04001846 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001847 {
Geoff Langef7b0162014-09-04 13:29:23 -04001848 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1849 if (error.isError())
1850 {
1851 return error;
1852 }
1853
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854 mDirtyImages = true;
1855 }
1856 else
1857 {
Geoff Langef7b0162014-09-04 13:29:23 -04001858 gl::Error error = ensureRenderTarget();
1859 if (error.isError())
1860 {
1861 return error;
1862 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863
1864 if (isValidLevel(level))
1865 {
Geoff Langef7b0162014-09-04 13:29:23 -04001866 error = updateStorageLevel(level);
1867 if (error.isError())
1868 {
1869 return error;
1870 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001871
Geoff Langef7b0162014-09-04 13:29:23 -04001872 error = mRenderer->copyImage3D(source, sourceRect,
1873 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1874 xoffset, yoffset, zoffset, mTexStorage, level);
1875 if (error.isError())
1876 {
1877 return error;
1878 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001879 }
1880 }
Geoff Langef7b0162014-09-04 13:29:23 -04001881
1882 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001883}
1884
Geoff Lang1f8532b2014-09-05 09:46:13 -04001885gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001886{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001887 ASSERT(target == GL_TEXTURE_3D);
1888
Brandon Jones78b1acd2014-07-15 15:33:07 -07001889 for (int level = 0; level < levels; level++)
1890 {
1891 GLsizei levelWidth = std::max(1, width >> level);
1892 GLsizei levelHeight = std::max(1, height >> level);
1893 GLsizei levelDepth = std::max(1, depth >> level);
1894 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1895 }
1896
1897 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1898 {
1899 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1900 }
1901
Geoff Lang1f8532b2014-09-05 09:46:13 -04001902 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001903 bool renderTarget = IsRenderTargetUsage(mUsage);
1904 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001905
1906 gl::Error error = setCompleteTexStorage(storage);
1907 if (error.isError())
1908 {
1909 SafeDelete(storage);
1910 return error;
1911 }
1912
1913 mImmutable = true;
1914
1915 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001916}
1917
Brandon Jones6053a522014-07-25 16:22:09 -07001918void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001919{
Brandon Jones6053a522014-07-25 16:22:09 -07001920 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001921}
1922
Brandon Jones6053a522014-07-25 16:22:09 -07001923void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001924{
Brandon Jones6053a522014-07-25 16:22:09 -07001925 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001926}
1927
Brandon Jones6053a522014-07-25 16:22:09 -07001928
Jamie Madill4aa79e12014-09-29 10:46:14 -04001929void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001930{
1931 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1932 int levelCount = mipLevels();
1933 for (int level = 1; level < levelCount; level++)
1934 {
1935 redefineImage(level, getBaseLevelInternalFormat(),
1936 std::max(getBaseLevelWidth() >> level, 1),
1937 std::max(getBaseLevelHeight() >> level, 1),
1938 std::max(getBaseLevelDepth() >> level, 1));
1939 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001940}
1941
Jamie Madillac7579c2014-09-17 16:59:33 -04001942unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001943{
Geoff Langef7b0162014-09-04 13:29:23 -04001944 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001945}
1946
Geoff Lang64f23f62014-09-10 14:40:12 -04001947gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001948{
1949 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001950 gl::Error error = ensureRenderTarget();
1951 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001952 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001953 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001954 }
1955
Jamie Madillac7579c2014-09-17 16:59:33 -04001956 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001957 {
Geoff Langef7b0162014-09-04 13:29:23 -04001958 error = updateStorage();
1959 if (error.isError())
1960 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001961 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001962 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001963 }
1964 else
1965 {
Geoff Langef7b0162014-09-04 13:29:23 -04001966 error = updateStorageLevel(index.mipIndex);
1967 if (error.isError())
1968 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001969 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001970 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001971 }
1972
Geoff Lang64f23f62014-09-10 14:40:12 -04001973 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001974}
1975
Geoff Langef7b0162014-09-04 13:29:23 -04001976gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001977{
1978 // Only initialize the first time this texture is used as a render target or shader resource
1979 if (mTexStorage)
1980 {
Geoff Langef7b0162014-09-04 13:29:23 -04001981 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001982 }
1983
1984 // do not attempt to create storage for nonexistant data
1985 if (!isLevelComplete(0))
1986 {
Geoff Langef7b0162014-09-04 13:29:23 -04001987 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001988 }
1989
1990 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
1991
Geoff Langef7b0162014-09-04 13:29:23 -04001992 rx::TextureStorage *storage = NULL;
1993 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1994 if (error.isError())
1995 {
1996 return error;
1997 }
1998
1999 error = setCompleteTexStorage(storage);
2000 if (error.isError())
2001 {
2002 SafeDelete(storage);
2003 return error;
2004 }
2005
Brandon Jones78b1acd2014-07-15 15:33:07 -07002006 ASSERT(mTexStorage);
2007
2008 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002009 error = updateStorage();
2010 if (error.isError())
2011 {
2012 return error;
2013 }
2014
2015 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002016}
2017
Geoff Langef7b0162014-09-04 13:29:23 -04002018gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002019{
2020 GLsizei width = getBaseLevelWidth();
2021 GLsizei height = getBaseLevelHeight();
2022 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002023 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002024
2025 ASSERT(width > 0 && height > 0 && depth > 0);
2026
2027 // use existing storage level count, when previously specified by TexStorage*D
2028 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2029
Geoff Langef7b0162014-09-04 13:29:23 -04002030 // TODO: Verify creation of the storage succeeded
2031 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2032
2033 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002034}
2035
Geoff Langef7b0162014-09-04 13:29:23 -04002036gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002037{
2038 SafeDelete(mTexStorage);
2039 mTexStorage = newCompleteTexStorage;
2040 mDirtyImages = true;
2041
2042 // We do not support managed 3D storage, as that is D3D9/ES2-only
2043 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002044
2045 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002046}
2047
Geoff Langef7b0162014-09-04 13:29:23 -04002048gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002049{
2050 ASSERT(mTexStorage != NULL);
2051 GLint storageLevels = mTexStorage->getLevelCount();
2052 for (int level = 0; level < storageLevels; level++)
2053 {
2054 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2055 {
Geoff Langef7b0162014-09-04 13:29:23 -04002056 gl::Error error = updateStorageLevel(level);
2057 if (error.isError())
2058 {
2059 return error;
2060 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002061 }
2062 }
Geoff Langef7b0162014-09-04 13:29:23 -04002063
2064 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002065}
2066
Brandon Jones78b1acd2014-07-15 15:33:07 -07002067bool TextureD3D_3D::isValidLevel(int level) const
2068{
2069 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2070}
2071
2072bool TextureD3D_3D::isLevelComplete(int level) const
2073{
2074 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2075
2076 if (isImmutable())
2077 {
2078 return true;
2079 }
2080
2081 GLsizei width = getBaseLevelWidth();
2082 GLsizei height = getBaseLevelHeight();
2083 GLsizei depth = getBaseLevelDepth();
2084
2085 if (width <= 0 || height <= 0 || depth <= 0)
2086 {
2087 return false;
2088 }
2089
2090 if (level == 0)
2091 {
2092 return true;
2093 }
2094
2095 ImageD3D *levelImage = mImageArray[level];
2096
2097 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2098 {
2099 return false;
2100 }
2101
2102 if (levelImage->getWidth() != std::max(1, width >> level))
2103 {
2104 return false;
2105 }
2106
2107 if (levelImage->getHeight() != std::max(1, height >> level))
2108 {
2109 return false;
2110 }
2111
2112 if (levelImage->getDepth() != std::max(1, depth >> level))
2113 {
2114 return false;
2115 }
2116
2117 return true;
2118}
2119
Jamie Madille76bdda2014-10-20 17:13:52 -04002120bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2121{
2122 return isLevelComplete(index.mipIndex);
2123}
2124
Geoff Langef7b0162014-09-04 13:29:23 -04002125gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002126{
2127 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2128 ASSERT(isLevelComplete(level));
2129
2130 if (mImageArray[level]->isDirty())
2131 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002132 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2133 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002134 gl::Error error = commitRegion(index, region);
2135 if (error.isError())
2136 {
2137 return error;
2138 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002139 }
Geoff Langef7b0162014-09-04 13:29:23 -04002140
2141 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002142}
2143
2144void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2145{
2146 // If there currently is a corresponding storage texture image, it has these parameters
2147 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2148 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2149 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2150 const GLenum storageFormat = getBaseLevelInternalFormat();
2151
2152 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2153
2154 if (mTexStorage)
2155 {
2156 const int storageLevels = mTexStorage->getLevelCount();
2157
2158 if ((level >= storageLevels && storageLevels != 0) ||
2159 width != storageWidth ||
2160 height != storageHeight ||
2161 depth != storageDepth ||
2162 internalformat != storageFormat) // Discard mismatched storage
2163 {
2164 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2165 {
2166 mImageArray[i]->markDirty();
2167 }
2168
2169 SafeDelete(mTexStorage);
2170 mDirtyImages = true;
2171 }
2172 }
2173}
2174
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002175gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2176{
2177 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2178 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2179}
Brandon Jones142ec422014-07-16 10:31:30 -07002180
Jamie Madillcb83dc12014-09-29 10:46:12 -04002181gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2182{
2183 // The "layer" here does not apply to 3D images. We use one Image per mip.
2184 return gl::ImageIndex::Make3D(mip);
2185}
2186
Jamie Madill710e5772014-10-20 17:13:53 -04002187bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2188{
2189 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2190 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2191}
2192
Brandon Jones142ec422014-07-16 10:31:30 -07002193TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002194 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002195{
2196 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2197 {
2198 mLayerCounts[level] = 0;
2199 mImageArray[level] = NULL;
2200 }
2201}
2202
2203TextureD3D_2DArray::~TextureD3D_2DArray()
2204{
Austin Kinross69822602014-08-12 15:51:37 -07002205 // Delete the Images before the TextureStorage.
2206 // Images might be relying on the TextureStorage for some of their data.
2207 // 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 -07002208 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002209 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002210}
2211
Brandon Jones142ec422014-07-16 10:31:30 -07002212Image *TextureD3D_2DArray::getImage(int level, int layer) const
2213{
2214 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2215 ASSERT(layer < mLayerCounts[level]);
2216 return mImageArray[level][layer];
2217}
2218
Jamie Madillfeda4d22014-09-17 13:03:29 -04002219Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2220{
2221 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2222 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2223 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2224 return mImageArray[index.mipIndex][index.layerIndex];
2225}
2226
Brandon Jones142ec422014-07-16 10:31:30 -07002227GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2228{
2229 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2230 return mLayerCounts[level];
2231}
2232
Brandon Jones142ec422014-07-16 10:31:30 -07002233GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2234{
2235 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2236}
2237
2238GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2239{
2240 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2241}
2242
Brandon Jones142ec422014-07-16 10:31:30 -07002243GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2244{
2245 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2246}
2247
2248bool TextureD3D_2DArray::isDepth(GLint level) const
2249{
Geoff Lang5d601382014-07-22 15:14:06 -04002250 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002251}
2252
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002253gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2254 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2255 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002256{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002257 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2258
Geoff Lang5d601382014-07-22 15:14:06 -04002259 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2260
Brandon Jones142ec422014-07-16 10:31:30 -07002261 redefineImage(level, sizedInternalFormat, width, height, depth);
2262
Geoff Lang5d601382014-07-22 15:14:06 -04002263 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2264 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002265
2266 for (int i = 0; i < depth; i++)
2267 {
2268 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002269 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2270 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002271 if (error.isError())
2272 {
2273 return error;
2274 }
Brandon Jones142ec422014-07-16 10:31:30 -07002275 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002276
2277 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002278}
2279
Geoff Langb5348332014-09-02 13:16:34 -04002280gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2281 GLsizei width, GLsizei height, GLsizei depth,
2282 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002283{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002284 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2285
Brandon Jones142ec422014-07-16 10:31:30 -07002286 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2287 redefineImage(level, format, width, height, depth);
2288
Geoff Lang5d601382014-07-22 15:14:06 -04002289 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2290 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002291
2292 for (int i = 0; i < depth; i++)
2293 {
2294 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Geoff Langb5348332014-09-02 13:16:34 -04002295 gl::Error error = TextureD3D::setCompressedImage(imageSize, layerPixels, mImageArray[level][i]);
2296 if (error.isError())
2297 {
2298 return error;
2299 }
Brandon Jones142ec422014-07-16 10:31:30 -07002300 }
Geoff Langb5348332014-09-02 13:16:34 -04002301
2302 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002303}
2304
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002305gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2306 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2307 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002308{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002309 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2310
Geoff Lang5d601382014-07-22 15:14:06 -04002311 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2312 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002313
2314 for (int i = 0; i < depth; i++)
2315 {
2316 int layer = zoffset + i;
2317 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2318
Jamie Madillfeda4d22014-09-17 13:03:29 -04002319 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002320 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2321 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002322 if (error.isError())
2323 {
2324 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002325 }
2326 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002327
2328 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002329}
2330
Geoff Langb5348332014-09-02 13:16:34 -04002331gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2332 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
2333 GLsizei imageSize, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002334{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002335 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2336
Geoff Lang5d601382014-07-22 15:14:06 -04002337 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2338 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002339
2340 for (int i = 0; i < depth; i++)
2341 {
2342 int layer = zoffset + i;
2343 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2344
Geoff Langb5348332014-09-02 13:16:34 -04002345 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
2346 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002347 {
Geoff Langb5348332014-09-02 13:16:34 -04002348 return error;
2349 }
2350
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002351 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2352 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2353 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002354 if (error.isError())
2355 {
2356 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002357 }
2358 }
Geoff Langb5348332014-09-02 13:16:34 -04002359
2360 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002361}
2362
Geoff Langef7b0162014-09-04 13:29:23 -04002363gl::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 -07002364{
2365 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002366 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002367}
2368
Geoff Langef7b0162014-09-04 13:29:23 -04002369gl::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 -07002370{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002371 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2372
Jamie Madill82bf0c52014-10-03 11:50:53 -04002373 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002374 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002375
Jamie Madille76bdda2014-10-20 17:13:52 -04002376 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002377 {
Geoff Langef7b0162014-09-04 13:29:23 -04002378 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2379 if (error.isError())
2380 {
2381 return error;
2382 }
2383
Brandon Jones142ec422014-07-16 10:31:30 -07002384 mDirtyImages = true;
2385 }
2386 else
2387 {
Geoff Langef7b0162014-09-04 13:29:23 -04002388 gl::Error error = ensureRenderTarget();
2389 if (error.isError())
2390 {
2391 return error;
2392 }
Brandon Jones142ec422014-07-16 10:31:30 -07002393
2394 if (isValidLevel(level))
2395 {
Geoff Langef7b0162014-09-04 13:29:23 -04002396 error = updateStorageLevel(level);
2397 if (error.isError())
2398 {
2399 return error;
2400 }
Brandon Jones142ec422014-07-16 10:31:30 -07002401
Geoff Langef7b0162014-09-04 13:29:23 -04002402 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2403 xoffset, yoffset, zoffset, mTexStorage, level);
2404 if (error.isError())
2405 {
2406 return error;
2407 }
Brandon Jones142ec422014-07-16 10:31:30 -07002408 }
2409 }
Geoff Langef7b0162014-09-04 13:29:23 -04002410 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002411}
2412
Geoff Lang1f8532b2014-09-05 09:46:13 -04002413gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002414{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002415 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2416
Brandon Jones142ec422014-07-16 10:31:30 -07002417 deleteImages();
2418
2419 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2420 {
2421 GLsizei levelWidth = std::max(1, width >> level);
2422 GLsizei levelHeight = std::max(1, height >> level);
2423
2424 mLayerCounts[level] = (level < levels ? depth : 0);
2425
2426 if (mLayerCounts[level] > 0)
2427 {
2428 // Create new images for this level
2429 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2430
2431 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2432 {
2433 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2434 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2435 levelHeight, 1, true);
2436 }
2437 }
2438 }
2439
Geoff Lang1f8532b2014-09-05 09:46:13 -04002440 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002441 bool renderTarget = IsRenderTargetUsage(mUsage);
2442 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002443
2444 gl::Error error = setCompleteTexStorage(storage);
2445 if (error.isError())
2446 {
2447 SafeDelete(storage);
2448 return error;
2449 }
2450
2451 mImmutable = true;
2452
2453 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002454}
2455
Brandon Jones6053a522014-07-25 16:22:09 -07002456void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002457{
Brandon Jones6053a522014-07-25 16:22:09 -07002458 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002459}
2460
Brandon Jones6053a522014-07-25 16:22:09 -07002461void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002462{
Brandon Jones6053a522014-07-25 16:22:09 -07002463 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002464}
2465
Brandon Jones6053a522014-07-25 16:22:09 -07002466
Jamie Madill4aa79e12014-09-29 10:46:14 -04002467void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002468{
2469 int baseWidth = getBaseLevelWidth();
2470 int baseHeight = getBaseLevelHeight();
2471 int baseDepth = getBaseLevelDepth();
2472 GLenum baseFormat = getBaseLevelInternalFormat();
2473
2474 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2475 int levelCount = mipLevels();
2476 for (int level = 1; level < levelCount; level++)
2477 {
2478 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2479 }
Brandon Jones142ec422014-07-16 10:31:30 -07002480}
2481
Jamie Madillac7579c2014-09-17 16:59:33 -04002482unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002483{
Geoff Langef7b0162014-09-04 13:29:23 -04002484 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002485}
2486
Geoff Lang64f23f62014-09-10 14:40:12 -04002487gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002488{
2489 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002490 gl::Error error = ensureRenderTarget();
2491 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002492 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002493 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002494 }
2495
Geoff Langef7b0162014-09-04 13:29:23 -04002496 error = updateStorageLevel(index.mipIndex);
2497 if (error.isError())
2498 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002499 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002500 }
2501
Geoff Lang64f23f62014-09-10 14:40:12 -04002502 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002503}
2504
Geoff Langef7b0162014-09-04 13:29:23 -04002505gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002506{
2507 // Only initialize the first time this texture is used as a render target or shader resource
2508 if (mTexStorage)
2509 {
Geoff Langef7b0162014-09-04 13:29:23 -04002510 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002511 }
2512
2513 // do not attempt to create storage for nonexistant data
2514 if (!isLevelComplete(0))
2515 {
Geoff Langef7b0162014-09-04 13:29:23 -04002516 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002517 }
2518
2519 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2520
Geoff Langef7b0162014-09-04 13:29:23 -04002521 TextureStorage *storage = NULL;
2522 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2523 if (error.isError())
2524 {
2525 return error;
2526 }
2527
2528 error = setCompleteTexStorage(storage);
2529 if (error.isError())
2530 {
2531 SafeDelete(storage);
2532 return error;
2533 }
2534
Brandon Jones142ec422014-07-16 10:31:30 -07002535 ASSERT(mTexStorage);
2536
2537 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002538 error = updateStorage();
2539 if (error.isError())
2540 {
2541 return error;
2542 }
2543
2544 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002545}
2546
Geoff Langef7b0162014-09-04 13:29:23 -04002547gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002548{
2549 GLsizei width = getBaseLevelWidth();
2550 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002551 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002552 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002553
2554 ASSERT(width > 0 && height > 0 && depth > 0);
2555
2556 // use existing storage level count, when previously specified by TexStorage*D
2557 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2558
Geoff Langef7b0162014-09-04 13:29:23 -04002559 // TODO(geofflang): Verify storage creation succeeds
2560 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2561
2562 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002563}
2564
Geoff Langef7b0162014-09-04 13:29:23 -04002565gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002566{
2567 SafeDelete(mTexStorage);
2568 mTexStorage = newCompleteTexStorage;
2569 mDirtyImages = true;
2570
2571 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2572 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002573
2574 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002575}
2576
Geoff Langef7b0162014-09-04 13:29:23 -04002577gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002578{
2579 ASSERT(mTexStorage != NULL);
2580 GLint storageLevels = mTexStorage->getLevelCount();
2581 for (int level = 0; level < storageLevels; level++)
2582 {
2583 if (isLevelComplete(level))
2584 {
Geoff Langef7b0162014-09-04 13:29:23 -04002585 gl::Error error = updateStorageLevel(level);
2586 if (error.isError())
2587 {
2588 return error;
2589 }
Brandon Jones142ec422014-07-16 10:31:30 -07002590 }
2591 }
Geoff Langef7b0162014-09-04 13:29:23 -04002592
2593 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002594}
2595
Brandon Jones142ec422014-07-16 10:31:30 -07002596bool TextureD3D_2DArray::isValidLevel(int level) const
2597{
2598 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2599}
2600
2601bool TextureD3D_2DArray::isLevelComplete(int level) const
2602{
2603 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2604
2605 if (isImmutable())
2606 {
2607 return true;
2608 }
2609
2610 GLsizei width = getBaseLevelWidth();
2611 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002612 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002613
2614 if (width <= 0 || height <= 0 || layers <= 0)
2615 {
2616 return false;
2617 }
2618
2619 if (level == 0)
2620 {
2621 return true;
2622 }
2623
2624 if (getInternalFormat(level) != getInternalFormat(0))
2625 {
2626 return false;
2627 }
2628
2629 if (getWidth(level) != std::max(1, width >> level))
2630 {
2631 return false;
2632 }
2633
2634 if (getHeight(level) != std::max(1, height >> level))
2635 {
2636 return false;
2637 }
2638
Jamie Madill3269bcb2014-09-30 16:33:52 -04002639 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002640 {
2641 return false;
2642 }
2643
2644 return true;
2645}
2646
Jamie Madille76bdda2014-10-20 17:13:52 -04002647bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2648{
2649 return isLevelComplete(index.mipIndex);
2650}
2651
Geoff Langef7b0162014-09-04 13:29:23 -04002652gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002653{
2654 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2655 ASSERT(isLevelComplete(level));
2656
2657 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2658 {
2659 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2660 if (mImageArray[level][layer]->isDirty())
2661 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002662 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2663 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002664 gl::Error error = commitRegion(index, region);
2665 if (error.isError())
2666 {
2667 return error;
2668 }
Brandon Jones142ec422014-07-16 10:31:30 -07002669 }
2670 }
Geoff Langef7b0162014-09-04 13:29:23 -04002671
2672 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002673}
2674
2675void TextureD3D_2DArray::deleteImages()
2676{
2677 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2678 {
2679 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2680 {
2681 delete mImageArray[level][layer];
2682 }
2683 delete[] mImageArray[level];
2684 mImageArray[level] = NULL;
2685 mLayerCounts[level] = 0;
2686 }
2687}
2688
2689void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2690{
2691 // If there currently is a corresponding storage texture image, it has these parameters
2692 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2693 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002694 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002695 const GLenum storageFormat = getBaseLevelInternalFormat();
2696
2697 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2698 {
2699 delete mImageArray[level][layer];
2700 }
2701 delete[] mImageArray[level];
2702 mImageArray[level] = NULL;
2703 mLayerCounts[level] = depth;
2704
2705 if (depth > 0)
2706 {
2707 mImageArray[level] = new ImageD3D*[depth]();
2708
2709 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2710 {
2711 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2712 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2713 }
2714 }
2715
2716 if (mTexStorage)
2717 {
2718 const int storageLevels = mTexStorage->getLevelCount();
2719
2720 if ((level >= storageLevels && storageLevels != 0) ||
2721 width != storageWidth ||
2722 height != storageHeight ||
2723 depth != storageDepth ||
2724 internalformat != storageFormat) // Discard mismatched storage
2725 {
2726 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2727 {
2728 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2729 {
2730 mImageArray[level][layer]->markDirty();
2731 }
2732 }
2733
2734 delete mTexStorage;
2735 mTexStorage = NULL;
2736 mDirtyImages = true;
2737 }
2738 }
2739}
2740
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002741gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2742{
2743 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2744}
2745
Jamie Madillcb83dc12014-09-29 10:46:12 -04002746gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2747{
2748 return gl::ImageIndex::Make2DArray(mip, layer);
2749}
2750
Jamie Madill710e5772014-10-20 17:13:53 -04002751bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2752{
2753 // Check for having a storage and the right type of index
2754 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2755 {
2756 return false;
2757 }
2758
2759 // Check the mip index
2760 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2761 {
2762 return false;
2763 }
2764
2765 // Check the layer index
2766 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2767}
2768
Brandon Jones78b1acd2014-07-15 15:33:07 -07002769}