blob: b53ef6cf9a7bae5ad0136f33a646c1cc461a5fc4 [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
Jamie Madillfb0580a2014-11-27 14:03:52 -05009#include "libANGLE/renderer/d3d/TextureD3D.h"
10
11#include "common/mathutil.h"
12#include "common/utilities.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050013#include "libANGLE/Buffer.h"
14#include "libANGLE/Framebuffer.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050015#include "libANGLE/Surface.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050016#include "libANGLE/Texture.h"
17#include "libANGLE/formatutils.h"
18#include "libANGLE/renderer/BufferImpl.h"
19#include "libANGLE/renderer/RenderTarget.h"
20#include "libANGLE/renderer/d3d/BufferD3D.h"
Geoff Lang2b5420c2014-11-19 14:20:15 -050021#include "libANGLE/renderer/d3d/ImageD3D.h"
22#include "libANGLE/renderer/d3d/RendererD3D.h"
Jamie Madillfb0580a2014-11-27 14:03:52 -050023#include "libANGLE/renderer/d3d/SurfaceD3D.h"
24#include "libANGLE/renderer/d3d/TextureStorage.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
Geoff Lang0a4f1e22014-12-17 12:33:26 -050032gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const uint8_t **pointerOut)
Jamie Madillc751d1e2014-10-21 17:46:29 -040033{
34 if (unpack.pixelBuffer.id() != 0)
35 {
36 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
37 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
38 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
39
40 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
41 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
Jamie Madill9ae396b2014-10-21 17:46:30 -040042 BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation());
43 ASSERT(bufferD3D);
Jamie Madillc751d1e2014-10-21 17:46:29 -040044 const uint8_t *bufferData = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -040045 gl::Error error = bufferD3D->getData(&bufferData);
Jamie Madillc751d1e2014-10-21 17:46:29 -040046 if (error.isError())
47 {
48 return error;
49 }
50
51 *pointerOut = bufferData + offset;
52 }
53 else
54 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -050055 *pointerOut = pixels;
Jamie Madillc751d1e2014-10-21 17:46:29 -040056 }
57
58 return gl::Error(GL_NO_ERROR);
59}
60
Brandon Jonesf47bebc2014-07-09 14:28:42 -070061bool IsRenderTargetUsage(GLenum usage)
62{
63 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
64}
65
Jamie Madillc751d1e2014-10-21 17:46:29 -040066}
67
Jamie Madill93e13fb2014-11-06 15:27:25 -050068TextureD3D::TextureD3D(RendererD3D *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070069 : mRenderer(renderer),
70 mUsage(GL_NONE),
71 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040072 mImmutable(false),
73 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070074{
75}
76
77TextureD3D::~TextureD3D()
78{
79}
80
Brandon Jones6053a522014-07-25 16:22:09 -070081TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
82{
83 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
84 return static_cast<TextureD3D*>(texture);
85}
86
Jamie Madill2f06dbf2014-09-18 15:08:50 -040087TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070088{
89 // ensure the underlying texture is created
90 initializeStorage(false);
91
Jamie Madill98553e32014-09-30 16:33:50 -040092 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070093 {
94 updateStorage();
95 }
96
Jamie Madill98553e32014-09-30 16:33:50 -040097 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070098}
99
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700100GLint TextureD3D::getBaseLevelWidth() const
101{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700102 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700103 return (baseImage ? baseImage->getWidth() : 0);
104}
105
106GLint TextureD3D::getBaseLevelHeight() const
107{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700108 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700109 return (baseImage ? baseImage->getHeight() : 0);
110}
111
112GLint TextureD3D::getBaseLevelDepth() const
113{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700114 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700115 return (baseImage ? baseImage->getDepth() : 0);
116}
117
118// Note: "base level image" is loosely defined to be any image from the base level,
119// where in the base of 2D array textures and cube maps there are several. Don't use
120// the base level image for anything except querying texture format and size.
121GLenum TextureD3D::getBaseLevelInternalFormat() const
122{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700123 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700124 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
125}
126
Jamie Madillec6de4e2014-10-20 10:59:56 -0400127bool TextureD3D::shouldUseSetData(const Image *image) const
128{
129 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
130 {
131 return false;
132 }
133
134 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
135
136 // We can only handle full updates for depth-stencil textures, so to avoid complications
137 // disable them entirely.
138 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
139 {
140 return false;
141 }
142
143 // TODO(jmadill): Handle compressed internal formats
144 return (mTexStorage && !internalFormat.compressed);
145}
146
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500147gl::Error TextureD3D::setImage(const gl::ImageIndex &index, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700148{
Jamie Madillba6bc952014-10-06 10:56:22 -0400149 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400150 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400151
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700152 // No-op
153 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
154 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400155 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700156 }
157
158 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
159 // 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 -0400160 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400161 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
162 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700163 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400164 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700165 }
166
167 if (pixelData != NULL)
168 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400169 gl::Error error(GL_NO_ERROR);
170
Jamie Madillec6de4e2014-10-20 10:59:56 -0400171 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400172 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400173 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400174 }
175 else
176 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500177 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
178 error = image->loadData(fullImageArea, unpack.alignment, type, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400179 }
180
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400181 if (error.isError())
182 {
183 return error;
184 }
185
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700186 mDirtyImages = true;
187 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400188
189 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700190}
191
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500192gl::Error TextureD3D::subImage(const gl::ImageIndex &index, const gl::Box &area, GLenum format, GLenum type,
193 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400196 const uint8_t *pixelData = NULL;
197 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
198 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700199 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400200 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700201 }
202
203 if (pixelData != NULL)
204 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400205 Image *image = getImage(index);
206 ASSERT(image);
207
Jamie Madillec6de4e2014-10-20 10:59:56 -0400208 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500210 return mTexStorage->setData(index, image, &area, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400211 }
212
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500213 gl::Error error = image->loadData(area, unpack.alignment, type, pixelData);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400214 if (error.isError())
215 {
216 return error;
217 }
218
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500219 error = commitRegion(index, area);
Jamie Madille6b6da02014-10-02 11:03:14 -0400220 if (error.isError())
221 {
222 return error;
223 }
224
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700225 mDirtyImages = true;
226 }
227
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400228 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700229}
230
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500231gl::Error TextureD3D::setCompressedImage(const gl::ImageIndex &index, const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700232{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400233 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
234 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
235 const uint8_t *pixelData = NULL;
236 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
237 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700238 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400239 return error;
240 }
241
242 if (pixelData != NULL)
243 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500244 Image *image = getImage(index);
245 ASSERT(image);
246
247 gl::Box fullImageArea(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
248 gl::Error error = image->loadCompressedData(fullImageArea, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400249 if (error.isError())
250 {
251 return error;
252 }
253
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700254 mDirtyImages = true;
255 }
Geoff Langb5348332014-09-02 13:16:34 -0400256
257 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700258}
259
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500260gl::Error TextureD3D::subImageCompressed(const gl::ImageIndex &index, const gl::Box &area, GLenum format,
261 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700262{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400263 const uint8_t *pixelData = NULL;
264 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
265 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700266 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400267 return error;
268 }
269
270 if (pixelData != NULL)
271 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500272 Image *image = getImage(index);
273 ASSERT(image);
274
275 gl::Error error = image->loadCompressedData(area, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400276 if (error.isError())
277 {
278 return error;
279 }
280
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700281 mDirtyImages = true;
282 }
283
Geoff Langb5348332014-09-02 13:16:34 -0400284 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700285}
286
287bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
288{
289 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
290}
291
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500292gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const uint8_t *pixels, const gl::Box &destArea,
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400293 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400295 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700296 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
297 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400298 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700299 }
300
301 // In order to perform the fast copy through the shader, we must have the right format, and be able
302 // to create a render target.
303 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
304
Jacek Cabana5521de2014-10-01 17:23:46 +0200305 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700306
Geoff Langae5122c2014-08-27 14:08:43 -0400307 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
308 if (error.isError())
309 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400310 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400311 }
312
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400313 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700314}
315
316GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
317{
318 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
319 {
320 // Maximum number of levels
321 return gl::log2(std::max(std::max(width, height), depth)) + 1;
322 }
323 else
324 {
325 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
326 return 1;
327 }
328}
329
330int TextureD3D::mipLevels() const
331{
332 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
333}
334
Jamie Madill98553e32014-09-30 16:33:50 -0400335TextureStorage *TextureD3D::getStorage()
336{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400337 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400338 return mTexStorage;
339}
340
Jamie Madill3269bcb2014-09-30 16:33:52 -0400341Image *TextureD3D::getBaseLevelImage() const
342{
343 return getImage(getImageIndex(0, 0));
344}
345
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400346gl::Error TextureD3D::generateMipmaps()
Jamie Madill4aa79e12014-09-29 10:46:14 -0400347{
Jamie Madill9aca0592014-10-06 16:26:59 -0400348 GLint mipCount = mipLevels();
349
350 if (mipCount == 1)
351 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400352 return gl::Error(GL_NO_ERROR); // no-op
Jamie Madill9aca0592014-10-06 16:26:59 -0400353 }
354
355 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400356 initMipmapsImages();
357
358 // We know that all layers have the same dimension, for the texture to be complete
359 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400360
Jamie Madill9aca0592014-10-06 16:26:59 -0400361 // When making mipmaps with the setData workaround enabled, the texture storage has
362 // the image data already. For non-render-target storage, we have to pull it out into
363 // an image layer.
364 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
365 {
366 if (!mTexStorage->isRenderTarget())
367 {
368 // Copy from the storage mip 0 to Image mip 0
369 for (GLint layer = 0; layer < layerCount; ++layer)
370 {
371 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400372
Jamie Madill9aca0592014-10-06 16:26:59 -0400373 Image *image = getImage(srcIndex);
374 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500375 gl::Offset offset(0, 0, 0);
376 gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400377 if (error.isError())
378 {
379 return error;
380 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400381 }
382 }
383 else
384 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400385 gl::Error error = updateStorage();
386 if (error.isError())
387 {
388 return error;
389 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400390 }
391 }
392
393 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400394
395 for (GLint layer = 0; layer < layerCount; ++layer)
396 {
397 for (GLint mip = 1; mip < mipCount; ++mip)
398 {
399 ASSERT(getLayerCount(mip) == layerCount);
400
401 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
402 gl::ImageIndex destIndex = getImageIndex(mip, layer);
403
404 if (renderableStorage)
405 {
406 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400407 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
408 if (error.isError())
409 {
410 return error;
411 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400412 }
413 else
414 {
415 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400416 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
417 if (error.isError())
418 {
419 return error;
420 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400421 }
422 }
423 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400424
425 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400426}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700427
Jamie Madill135570a2014-09-30 16:33:51 -0400428bool TextureD3D::isBaseImageZeroSize() const
429{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400430 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400431
432 if (!baseImage || baseImage->getWidth() <= 0)
433 {
434 return true;
435 }
436
437 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
438 {
439 return true;
440 }
441
442 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
443 {
444 return true;
445 }
446
447 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
448 {
449 return true;
450 }
451
452 return false;
453}
454
Geoff Langef7b0162014-09-04 13:29:23 -0400455gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400456{
Geoff Langef7b0162014-09-04 13:29:23 -0400457 gl::Error error = initializeStorage(true);
458 if (error.isError())
459 {
460 return error;
461 }
Jamie Madill135570a2014-09-30 16:33:51 -0400462
463 if (!isBaseImageZeroSize())
464 {
465 ASSERT(mTexStorage);
466 if (!mTexStorage->isRenderTarget())
467 {
Geoff Langef7b0162014-09-04 13:29:23 -0400468 TextureStorage *newRenderTargetStorage = NULL;
469 error = createCompleteStorage(true, &newRenderTargetStorage);
470 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400471 {
Geoff Langef7b0162014-09-04 13:29:23 -0400472 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400473 }
474
Geoff Langef7b0162014-09-04 13:29:23 -0400475 error = mTexStorage->copyToStorage(newRenderTargetStorage);
476 if (error.isError())
477 {
478 SafeDelete(newRenderTargetStorage);
479 return error;
480 }
481
482 error = setCompleteTexStorage(newRenderTargetStorage);
483 if (error.isError())
484 {
485 SafeDelete(newRenderTargetStorage);
486 return error;
487 }
Jamie Madill135570a2014-09-30 16:33:51 -0400488 }
489 }
490
Geoff Langef7b0162014-09-04 13:29:23 -0400491 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400492}
493
Jamie Madille76bdda2014-10-20 17:13:52 -0400494bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
495{
Jamie Madill30d6c252014-11-13 10:03:33 -0500496 Image *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400497 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
498 return (image->isRenderableFormat() && levelsComplete);
499}
500
Jamie Madill710e5772014-10-20 17:13:53 -0400501gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
502{
503 if (mTexStorage)
504 {
505 ASSERT(isValidIndex(index));
506 Image *image = getImage(index);
507 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
508 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
509 if (error.isError())
510 {
511 return error;
512 }
513
514 image->markClean();
515 }
516
517 return gl::Error(GL_NO_ERROR);
518}
519
Jamie Madill93e13fb2014-11-06 15:27:25 -0500520TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400521 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700522{
523 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
524 {
525 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
526 }
527}
528
529TextureD3D_2D::~TextureD3D_2D()
530{
Austin Kinross69822602014-08-12 15:51:37 -0700531 // Delete the Images before the TextureStorage.
532 // Images might be relying on the TextureStorage for some of their data.
533 // 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 -0700534 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
535 {
536 delete mImageArray[i];
537 }
Austin Kinross69822602014-08-12 15:51:37 -0700538
539 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540}
541
Brandon Jonescef06ff2014-08-05 13:27:48 -0700542Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700543{
544 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700545 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700546 return mImageArray[level];
547}
548
Jamie Madillfeda4d22014-09-17 13:03:29 -0400549Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
550{
551 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400552 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400553 ASSERT(index.type == GL_TEXTURE_2D);
554 return mImageArray[index.mipIndex];
555}
556
Brandon Jonescef06ff2014-08-05 13:27:48 -0700557GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700559 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
560 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700561}
562
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700563GLsizei TextureD3D_2D::getWidth(GLint level) const
564{
565 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
566 return mImageArray[level]->getWidth();
567 else
568 return 0;
569}
570
571GLsizei TextureD3D_2D::getHeight(GLint level) const
572{
573 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
574 return mImageArray[level]->getHeight();
575 else
576 return 0;
577}
578
579GLenum TextureD3D_2D::getInternalFormat(GLint level) const
580{
581 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
582 return mImageArray[level]->getInternalFormat();
583 else
584 return GL_NONE;
585}
586
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700587bool TextureD3D_2D::isDepth(GLint level) const
588{
Geoff Lang5d601382014-07-22 15:14:06 -0400589 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700590}
591
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500592gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
593 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700594{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500595 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700596
Geoff Lang5d601382014-07-22 15:14:06 -0400597 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
598
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700599 bool fastUnpacked = false;
600
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500601 redefineImage(level, sizedInternalFormat, size);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700602
Jamie Madillba6bc952014-10-06 10:56:22 -0400603 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
604
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700605 // Attempt a fast gpu copy of the pixel data to the surface
606 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
607 {
608 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400609 RenderTarget *destRenderTarget = NULL;
610 gl::Error error = getRenderTarget(index, &destRenderTarget);
611 if (error.isError())
612 {
613 return error;
614 }
615
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700616 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
617
Geoff Lang64f23f62014-09-10 14:40:12 -0400618 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
619 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700620 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400621 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700622 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400623
624 // Ensure we don't overwrite our newly initialized data
625 mImageArray[level]->markClean();
626
627 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700628 }
629
630 if (!fastUnpacked)
631 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500632 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400633 if (error.isError())
634 {
635 return error;
636 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700637 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400638
639 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700640}
641
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500642gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
643 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700644{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500645 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700646
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700647 bool fastUnpacked = false;
648
Jamie Madillac7579c2014-09-17 16:59:33 -0400649 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700650 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
651 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400652 RenderTarget *renderTarget = NULL;
653 gl::Error error = getRenderTarget(index, &renderTarget);
654 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700655 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400656 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700657 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400658
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500659 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -0400660 if (error.isError())
661 {
662 return error;
663 }
664
665 // Ensure we don't overwrite our newly initialized data
666 mImageArray[level]->markClean();
667
668 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700669 }
670
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400671 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500673 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400675
676 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700677}
678
Brandon Jonescef06ff2014-08-05 13:27:48 -0700679
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500680gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
681 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
682{
683 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
684
685 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
686 redefineImage(level, internalFormat, size);
687
688 return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels);
689}
690
691gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
692 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
693{
694 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
695
696 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
697 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -0400698 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700699 {
Geoff Langb5348332014-09-02 13:16:34 -0400700 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700701 }
Geoff Langb5348332014-09-02 13:16:34 -0400702
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500703 return commitRegion(index, area);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700704}
705
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500706gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
707 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700708{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700709 ASSERT(target == GL_TEXTURE_2D);
710
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500711 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
712 redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1));
Brandon Jonescef06ff2014-08-05 13:27:48 -0700713
Jamie Madille76bdda2014-10-20 17:13:52 -0400714 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500715 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400716
Jamie Madille76bdda2014-10-20 17:13:52 -0400717 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700718 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500719 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400720 if (error.isError())
721 {
722 return error;
723 }
724
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700725 mDirtyImages = true;
726 }
727 else
728 {
Geoff Langef7b0162014-09-04 13:29:23 -0400729 gl::Error error = ensureRenderTarget();
730 if (error.isError())
731 {
732 return error;
733 }
734
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700735 mImageArray[level]->markClean();
736
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500737 if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700738 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500739 gl::Error error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400740 if (error.isError())
741 {
742 return error;
743 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744 }
745 }
Geoff Langef7b0162014-09-04 13:29:23 -0400746
747 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700748}
749
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500750gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
751 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700752{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500753 ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700754
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700755 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
756 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700757
Jamie Madille76bdda2014-10-20 17:13:52 -0400758 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400759
Jamie Madille76bdda2014-10-20 17:13:52 -0400760 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700761 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500762 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400763 if (error.isError())
764 {
765 return error;
766 }
767
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700768 mDirtyImages = true;
769 }
770 else
771 {
Geoff Langef7b0162014-09-04 13:29:23 -0400772 gl::Error error = ensureRenderTarget();
773 if (error.isError())
774 {
775 return error;
776 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700777
778 if (isValidLevel(level))
779 {
Geoff Langef7b0162014-09-04 13:29:23 -0400780 error = updateStorageLevel(level);
781 if (error.isError())
782 {
783 return error;
784 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700785
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500786 error = mRenderer->copyImage2D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -0400787 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500788 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400789 if (error.isError())
790 {
791 return error;
792 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793 }
794 }
Geoff Langef7b0162014-09-04 13:29:23 -0400795
796 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700797}
798
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500799gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700800{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500801 ASSERT(GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700802
Geoff Lang8fed1f72015-01-09 11:09:33 -0500803 for (size_t level = 0; level < levels; level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700804 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500805 gl::Extents levelSize(std::max(1, size.width >> level),
806 std::max(1, size.height >> level),
807 1);
808 mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809 }
810
811 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
812 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500813 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700814 }
815
Geoff Lang1f8532b2014-09-05 09:46:13 -0400816 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400817 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500818 TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400819
820 gl::Error error = setCompleteTexStorage(storage);
821 if (error.isError())
822 {
823 SafeDelete(storage);
824 return error;
825 }
826
827 mImmutable = true;
828
829 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700830}
831
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700832void TextureD3D_2D::bindTexImage(egl::Surface *surface)
833{
834 GLenum internalformat = surface->getFormat();
835
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500836 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
837 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700838
839 if (mTexStorage)
840 {
841 SafeDelete(mTexStorage);
842 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400843
Jamie Madillfb0580a2014-11-27 14:03:52 -0500844 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
845 ASSERT(surfaceD3D);
846
847 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700848
849 mDirtyImages = true;
850}
851
852void TextureD3D_2D::releaseTexImage()
853{
854 if (mTexStorage)
855 {
856 SafeDelete(mTexStorage);
857 }
858
859 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
860 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500861 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700862 }
863}
864
Jamie Madill4aa79e12014-09-29 10:46:14 -0400865void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700867 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700868 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700869 for (int level = 1; level < levelCount; level++)
870 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500871 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
872 std::max(getBaseLevelHeight() >> level, 1),
873 1);
874
875 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700876 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700877}
878
Jamie Madillac7579c2014-09-17 16:59:33 -0400879unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700880{
Jamie Madillac7579c2014-09-17 16:59:33 -0400881 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400882 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700883}
884
Geoff Lang64f23f62014-09-10 14:40:12 -0400885gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700886{
Jamie Madillac7579c2014-09-17 16:59:33 -0400887 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700888
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700889 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400890 gl::Error error = ensureRenderTarget();
891 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700892 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400893 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700894 }
895
Geoff Langef7b0162014-09-04 13:29:23 -0400896 error = updateStorageLevel(index.mipIndex);
897 if (error.isError())
898 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400899 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400900 }
901
Geoff Lang64f23f62014-09-10 14:40:12 -0400902 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700903}
904
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700905bool TextureD3D_2D::isValidLevel(int level) const
906{
907 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
908}
909
910bool TextureD3D_2D::isLevelComplete(int level) const
911{
912 if (isImmutable())
913 {
914 return true;
915 }
916
Brandon Jones78b1acd2014-07-15 15:33:07 -0700917 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700918
919 GLsizei width = baseImage->getWidth();
920 GLsizei height = baseImage->getHeight();
921
922 if (width <= 0 || height <= 0)
923 {
924 return false;
925 }
926
927 // The base image level is complete if the width and height are positive
928 if (level == 0)
929 {
930 return true;
931 }
932
933 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700934 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700935
936 if (image->getInternalFormat() != baseImage->getInternalFormat())
937 {
938 return false;
939 }
940
941 if (image->getWidth() != std::max(1, width >> level))
942 {
943 return false;
944 }
945
946 if (image->getHeight() != std::max(1, height >> level))
947 {
948 return false;
949 }
950
951 return true;
952}
953
Jamie Madille76bdda2014-10-20 17:13:52 -0400954bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
955{
956 return isLevelComplete(index.mipIndex);
957}
958
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700959// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400960gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700961{
962 // Only initialize the first time this texture is used as a render target or shader resource
963 if (mTexStorage)
964 {
Geoff Langef7b0162014-09-04 13:29:23 -0400965 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700966 }
967
968 // do not attempt to create storage for nonexistant data
969 if (!isLevelComplete(0))
970 {
Geoff Langef7b0162014-09-04 13:29:23 -0400971 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700972 }
973
974 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
975
Geoff Langef7b0162014-09-04 13:29:23 -0400976 TextureStorage *storage = NULL;
977 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
978 if (error.isError())
979 {
980 return error;
981 }
982
983 error = setCompleteTexStorage(storage);
984 if (error.isError())
985 {
986 SafeDelete(storage);
987 return error;
988 }
989
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990 ASSERT(mTexStorage);
991
992 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400993 error = updateStorage();
994 if (error.isError())
995 {
996 return error;
997 }
998
999 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001000}
1001
Geoff Langef7b0162014-09-04 13:29:23 -04001002gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001003{
1004 GLsizei width = getBaseLevelWidth();
1005 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001006 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001007
1008 ASSERT(width > 0 && height > 0);
1009
1010 // use existing storage level count, when previously specified by TexStorage*D
1011 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1012
Geoff Langef7b0162014-09-04 13:29:23 -04001013 // TODO(geofflang): Determine if the texture creation succeeded
1014 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
1015
1016 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001017}
1018
Geoff Langef7b0162014-09-04 13:29:23 -04001019gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001020{
Geoff Langef7b0162014-09-04 13:29:23 -04001021 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001022 {
Geoff Langef7b0162014-09-04 13:29:23 -04001023 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001024 {
Geoff Langef7b0162014-09-04 13:29:23 -04001025 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1026 if (error.isError())
1027 {
1028 return error;
1029 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001030 }
1031 }
1032
Geoff Langef7b0162014-09-04 13:29:23 -04001033 SafeDelete(mTexStorage);
1034 mTexStorage = newCompleteTexStorage;
1035
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001036 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001037
1038 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001039}
1040
Geoff Langef7b0162014-09-04 13:29:23 -04001041gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001042{
1043 ASSERT(mTexStorage != NULL);
1044 GLint storageLevels = mTexStorage->getLevelCount();
1045 for (int level = 0; level < storageLevels; level++)
1046 {
1047 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1048 {
Geoff Langef7b0162014-09-04 13:29:23 -04001049 gl::Error error = updateStorageLevel(level);
1050 if (error.isError())
1051 {
1052 return error;
1053 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001054 }
1055 }
Geoff Langef7b0162014-09-04 13:29:23 -04001056
1057 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001058}
1059
Geoff Langef7b0162014-09-04 13:29:23 -04001060gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001061{
1062 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1063 ASSERT(isLevelComplete(level));
1064
1065 if (mImageArray[level]->isDirty())
1066 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001067 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1068 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001069 gl::Error error = commitRegion(index, region);
1070 if (error.isError())
1071 {
1072 return error;
1073 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001074 }
Geoff Langef7b0162014-09-04 13:29:23 -04001075
1076 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001077}
1078
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001079void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001080{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001081 ASSERT(size.depth == 1);
1082
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001083 // If there currently is a corresponding storage texture image, it has these parameters
1084 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1085 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1086 const GLenum storageFormat = getBaseLevelInternalFormat();
1087
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001088 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001089
1090 if (mTexStorage)
1091 {
1092 const int storageLevels = mTexStorage->getLevelCount();
1093
1094 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001095 size.width != storageWidth ||
1096 size.height != storageHeight ||
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001097 internalformat != storageFormat) // Discard mismatched storage
1098 {
1099 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1100 {
1101 mImageArray[i]->markDirty();
1102 }
1103
1104 SafeDelete(mTexStorage);
1105 mDirtyImages = true;
1106 }
1107 }
1108}
1109
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001110gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1111{
1112 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1113}
Brandon Jones0511e802014-07-14 16:27:26 -07001114
Jamie Madillcb83dc12014-09-29 10:46:12 -04001115gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1116{
1117 // "layer" does not apply to 2D Textures.
1118 return gl::ImageIndex::Make2D(mip);
1119}
1120
Jamie Madill710e5772014-10-20 17:13:53 -04001121bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1122{
1123 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1124 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1125}
1126
Jamie Madill93e13fb2014-11-06 15:27:25 -05001127TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001128 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001129{
1130 for (int i = 0; i < 6; i++)
1131 {
1132 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1133 {
1134 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1135 }
1136 }
1137}
1138
1139TextureD3D_Cube::~TextureD3D_Cube()
1140{
Austin Kinross69822602014-08-12 15:51:37 -07001141 // Delete the Images before the TextureStorage.
1142 // Images might be relying on the TextureStorage for some of their data.
1143 // 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 -07001144 for (int i = 0; i < 6; i++)
1145 {
1146 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1147 {
1148 SafeDelete(mImageArray[i][j]);
1149 }
1150 }
Austin Kinross69822602014-08-12 15:51:37 -07001151
1152 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001153}
1154
Brandon Jonescef06ff2014-08-05 13:27:48 -07001155Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001156{
1157 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001158 ASSERT(layer >= 0 && layer < 6);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001159 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001160}
1161
Jamie Madillfeda4d22014-09-17 13:03:29 -04001162Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1163{
1164 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001165 ASSERT(index.layerIndex >= 0 && index.layerIndex < 6);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001166 return mImageArray[index.layerIndex][index.mipIndex];
1167}
1168
Brandon Jonescef06ff2014-08-05 13:27:48 -07001169GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001171 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1172 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001173}
1174
Brandon Jonescef06ff2014-08-05 13:27:48 -07001175GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001176{
1177 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001178 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001179 else
1180 return GL_NONE;
1181}
1182
Brandon Jonescef06ff2014-08-05 13:27:48 -07001183bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001185 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001186}
1187
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001188gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1189 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001190{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001191 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001192
Geoff Lang5d601382014-07-22 15:14:06 -04001193 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001194 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001195
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001196 redefineImage(index.layerIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001197
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001198 return TextureD3D::setImage(index, type, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001199}
1200
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001201gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1202 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001203{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001204 ASSERT(area.depth == 1 && area.z == 0);
1205
1206 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
1207 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
1208}
1209
1210gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1211 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1212{
1213 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001214
Brandon Jones0511e802014-07-14 16:27:26 -07001215 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001216 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1217
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001218 redefineImage(faceIndex, level, internalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001219
Jamie Madillfeda4d22014-09-17 13:03:29 -04001220 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001221 return TextureD3D::setCompressedImage(index, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001222}
1223
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001224gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1225 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001226{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001227 ASSERT(area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001228
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001229 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001230
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001231 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001232 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001233 {
Geoff Langb5348332014-09-02 13:16:34 -04001234 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001235 }
Geoff Langb5348332014-09-02 13:16:34 -04001236
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001237 return commitRegion(index, area);
Brandon Jones0511e802014-07-14 16:27:26 -07001238}
1239
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001240gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1241 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001242{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001243 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001244 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04001245
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001246 gl::Extents size(sourceArea.width, sourceArea.height, 1);
1247 redefineImage(faceIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001248
Jamie Madille76bdda2014-10-20 17:13:52 -04001249 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001250 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001251
Jamie Madille76bdda2014-10-20 17:13:52 -04001252 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001253 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001254 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001255 if (error.isError())
1256 {
1257 return error;
1258 }
1259
Brandon Jones0511e802014-07-14 16:27:26 -07001260 mDirtyImages = true;
1261 }
1262 else
1263 {
Geoff Langef7b0162014-09-04 13:29:23 -04001264 gl::Error error = ensureRenderTarget();
1265 if (error.isError())
1266 {
1267 return error;
1268 }
1269
Brandon Jones0511e802014-07-14 16:27:26 -07001270 mImageArray[faceIndex][level]->markClean();
1271
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001272 ASSERT(size.width == size.height);
Brandon Jones0511e802014-07-14 16:27:26 -07001273
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001274 if (size.width > 0 && isValidFaceLevel(faceIndex, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001275 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001276 error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001277 if (error.isError())
1278 {
1279 return error;
1280 }
Brandon Jones0511e802014-07-14 16:27:26 -07001281 }
1282 }
Geoff Langef7b0162014-09-04 13:29:23 -04001283
1284 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001285}
1286
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001287gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1288 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001289{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001290 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001291
Jamie Madille76bdda2014-10-20 17:13:52 -04001292 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001293
Jamie Madille76bdda2014-10-20 17:13:52 -04001294 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001295 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001296 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001297 if (error.isError())
1298 {
1299 return error;
1300 }
1301
Brandon Jones0511e802014-07-14 16:27:26 -07001302 mDirtyImages = true;
1303 }
1304 else
1305 {
Geoff Langef7b0162014-09-04 13:29:23 -04001306 gl::Error error = ensureRenderTarget();
1307 if (error.isError())
1308 {
1309 return error;
1310 }
Brandon Jones0511e802014-07-14 16:27:26 -07001311
1312 if (isValidFaceLevel(faceIndex, level))
1313 {
Geoff Langef7b0162014-09-04 13:29:23 -04001314 error = updateStorageFaceLevel(faceIndex, level);
1315 if (error.isError())
1316 {
1317 return error;
1318 }
Brandon Jones0511e802014-07-14 16:27:26 -07001319
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001320 error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1321 destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001322 if (error.isError())
1323 {
1324 return error;
1325 }
Brandon Jones0511e802014-07-14 16:27:26 -07001326 }
1327 }
Geoff Langef7b0162014-09-04 13:29:23 -04001328
1329 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001330}
1331
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001332gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001333{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001334 ASSERT(size.width == size.height);
1335 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001336
Geoff Lang8fed1f72015-01-09 11:09:33 -05001337 for (size_t level = 0; level < levels; level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001338 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001339 GLsizei mipSize = std::max(1, size.width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001340 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1341 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001342 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001343 }
1344 }
1345
1346 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1347 {
1348 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1349 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001350 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001351 }
1352 }
1353
Geoff Lang1f8532b2014-09-05 09:46:13 -04001354 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001355 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001356 TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001357
1358 gl::Error error = setCompleteTexStorage(storage);
1359 if (error.isError())
1360 {
1361 SafeDelete(storage);
1362 return error;
1363 }
1364
1365 mImmutable = true;
1366
1367 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001368}
1369
Brandon Jones0511e802014-07-14 16:27:26 -07001370// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1371bool TextureD3D_Cube::isCubeComplete() const
1372{
1373 int baseWidth = getBaseLevelWidth();
1374 int baseHeight = getBaseLevelHeight();
1375 GLenum baseFormat = getBaseLevelInternalFormat();
1376
1377 if (baseWidth <= 0 || baseWidth != baseHeight)
1378 {
1379 return false;
1380 }
1381
1382 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1383 {
1384 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1385
1386 if (faceBaseImage.getWidth() != baseWidth ||
1387 faceBaseImage.getHeight() != baseHeight ||
1388 faceBaseImage.getInternalFormat() != baseFormat )
1389 {
1390 return false;
1391 }
1392 }
1393
1394 return true;
1395}
1396
Brandon Jones6053a522014-07-25 16:22:09 -07001397void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1398{
1399 UNREACHABLE();
1400}
1401
1402void TextureD3D_Cube::releaseTexImage()
1403{
1404 UNREACHABLE();
1405}
1406
1407
Jamie Madill4aa79e12014-09-29 10:46:14 -04001408void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001409{
1410 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1411 int levelCount = mipLevels();
1412 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1413 {
1414 for (int level = 1; level < levelCount; level++)
1415 {
1416 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001417 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1418 gl::Extents(faceLevelSize, faceLevelSize, 1));
Brandon Jones0511e802014-07-14 16:27:26 -07001419 }
1420 }
Brandon Jones0511e802014-07-14 16:27:26 -07001421}
1422
Jamie Madillac7579c2014-09-17 16:59:33 -04001423unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001424{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001425 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001426}
1427
Geoff Lang64f23f62014-09-10 14:40:12 -04001428gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001429{
Jamie Madillac7579c2014-09-17 16:59:33 -04001430 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001431
1432 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001433 gl::Error error = ensureRenderTarget();
1434 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001435 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001436 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001437 }
1438
Geoff Langef7b0162014-09-04 13:29:23 -04001439 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1440 if (error.isError())
1441 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001442 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001443 }
1444
Geoff Lang64f23f62014-09-10 14:40:12 -04001445 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001446}
1447
Geoff Langef7b0162014-09-04 13:29:23 -04001448gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001449{
1450 // Only initialize the first time this texture is used as a render target or shader resource
1451 if (mTexStorage)
1452 {
Geoff Langef7b0162014-09-04 13:29:23 -04001453 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001454 }
1455
1456 // do not attempt to create storage for nonexistant data
1457 if (!isFaceLevelComplete(0, 0))
1458 {
Geoff Langef7b0162014-09-04 13:29:23 -04001459 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001460 }
1461
1462 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1463
Geoff Langef7b0162014-09-04 13:29:23 -04001464 TextureStorage *storage = NULL;
1465 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1466 if (error.isError())
1467 {
1468 return error;
1469 }
1470
1471 error = setCompleteTexStorage(storage);
1472 if (error.isError())
1473 {
1474 SafeDelete(storage);
1475 return error;
1476 }
1477
Brandon Jones0511e802014-07-14 16:27:26 -07001478 ASSERT(mTexStorage);
1479
1480 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001481 error = updateStorage();
1482 if (error.isError())
1483 {
1484 return error;
1485 }
1486
1487 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001488}
1489
Geoff Langef7b0162014-09-04 13:29:23 -04001490gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001491{
1492 GLsizei size = getBaseLevelWidth();
1493
1494 ASSERT(size > 0);
1495
1496 // use existing storage level count, when previously specified by TexStorage*D
1497 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1498
Geoff Langef7b0162014-09-04 13:29:23 -04001499 // TODO (geofflang): detect if storage creation succeeded
1500 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1501
1502 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001503}
1504
Geoff Langef7b0162014-09-04 13:29:23 -04001505gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001506{
Geoff Langef7b0162014-09-04 13:29:23 -04001507 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001508 {
1509 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1510 {
Geoff Langef7b0162014-09-04 13:29:23 -04001511 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001512 {
Geoff Langef7b0162014-09-04 13:29:23 -04001513 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1514 if (error.isError())
1515 {
1516 return error;
1517 }
Brandon Jones0511e802014-07-14 16:27:26 -07001518 }
1519 }
1520 }
1521
Geoff Langef7b0162014-09-04 13:29:23 -04001522 SafeDelete(mTexStorage);
1523 mTexStorage = newCompleteTexStorage;
1524
Brandon Jones0511e802014-07-14 16:27:26 -07001525 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001526 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001527}
1528
Geoff Langef7b0162014-09-04 13:29:23 -04001529gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001530{
1531 ASSERT(mTexStorage != NULL);
1532 GLint storageLevels = mTexStorage->getLevelCount();
1533 for (int face = 0; face < 6; face++)
1534 {
1535 for (int level = 0; level < storageLevels; level++)
1536 {
1537 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1538 {
Geoff Langef7b0162014-09-04 13:29:23 -04001539 gl::Error error = updateStorageFaceLevel(face, level);
1540 if (error.isError())
1541 {
1542 return error;
1543 }
Brandon Jones0511e802014-07-14 16:27:26 -07001544 }
1545 }
1546 }
Geoff Langef7b0162014-09-04 13:29:23 -04001547
1548 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001549}
1550
Brandon Jones0511e802014-07-14 16:27:26 -07001551bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1552{
1553 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1554}
1555
Brandon Jones0511e802014-07-14 16:27:26 -07001556bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1557{
1558 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1559
1560 if (isImmutable())
1561 {
1562 return true;
1563 }
1564
1565 int baseSize = getBaseLevelWidth();
1566
1567 if (baseSize <= 0)
1568 {
1569 return false;
1570 }
1571
1572 // "isCubeComplete" checks for base level completeness and we must call that
1573 // to determine if any face at level 0 is complete. We omit that check here
1574 // to avoid re-checking cube-completeness for every face at level 0.
1575 if (level == 0)
1576 {
1577 return true;
1578 }
1579
1580 // Check that non-zero levels are consistent with the base level.
1581 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1582
1583 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1584 {
1585 return false;
1586 }
1587
1588 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1589 {
1590 return false;
1591 }
1592
1593 return true;
1594}
1595
Jamie Madille76bdda2014-10-20 17:13:52 -04001596bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1597{
1598 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1599}
1600
Geoff Langef7b0162014-09-04 13:29:23 -04001601gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001602{
1603 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1604 ImageD3D *image = mImageArray[faceIndex][level];
1605
1606 if (image->isDirty())
1607 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001608 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1609 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1610 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001611 gl::Error error = commitRegion(index, region);
1612 if (error.isError())
1613 {
1614 return error;
1615 }
Brandon Jones0511e802014-07-14 16:27:26 -07001616 }
Geoff Langef7b0162014-09-04 13:29:23 -04001617
1618 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001619}
1620
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001621void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001622{
1623 // If there currently is a corresponding storage texture image, it has these parameters
1624 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1625 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1626 const GLenum storageFormat = getBaseLevelInternalFormat();
1627
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001628 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001629
1630 if (mTexStorage)
1631 {
1632 const int storageLevels = mTexStorage->getLevelCount();
1633
1634 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001635 size.width != storageWidth ||
1636 size.height != storageHeight ||
Brandon Jones0511e802014-07-14 16:27:26 -07001637 internalformat != storageFormat) // Discard mismatched storage
1638 {
1639 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1640 {
1641 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1642 {
1643 mImageArray[faceIndex][level]->markDirty();
1644 }
1645 }
1646
1647 SafeDelete(mTexStorage);
1648
1649 mDirtyImages = true;
1650 }
1651 }
1652}
1653
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001654gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1655{
1656 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1657}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001658
Jamie Madillcb83dc12014-09-29 10:46:12 -04001659gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1660{
1661 // The "layer" of the image index corresponds to the cube face
1662 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1663}
1664
Jamie Madill710e5772014-10-20 17:13:53 -04001665bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1666{
1667 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1668 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1669}
1670
Jamie Madill93e13fb2014-11-06 15:27:25 -05001671TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001672 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001673{
1674 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1675 {
1676 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1677 }
1678}
1679
1680TextureD3D_3D::~TextureD3D_3D()
1681{
Austin Kinross69822602014-08-12 15:51:37 -07001682 // Delete the Images before the TextureStorage.
1683 // Images might be relying on the TextureStorage for some of their data.
1684 // 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 -07001685 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1686 {
1687 delete mImageArray[i];
1688 }
Austin Kinross69822602014-08-12 15:51:37 -07001689
1690 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001691}
1692
Brandon Jonescef06ff2014-08-05 13:27:48 -07001693Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001694{
1695 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001696 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697 return mImageArray[level];
1698}
1699
Jamie Madillfeda4d22014-09-17 13:03:29 -04001700Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1701{
1702 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001703 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001704 ASSERT(index.type == GL_TEXTURE_3D);
1705 return mImageArray[index.mipIndex];
1706}
1707
Brandon Jonescef06ff2014-08-05 13:27:48 -07001708GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001709{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001710 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1711 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001712}
1713
Brandon Jones78b1acd2014-07-15 15:33:07 -07001714GLsizei TextureD3D_3D::getWidth(GLint level) const
1715{
1716 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1717 return mImageArray[level]->getWidth();
1718 else
1719 return 0;
1720}
1721
1722GLsizei TextureD3D_3D::getHeight(GLint level) const
1723{
1724 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1725 return mImageArray[level]->getHeight();
1726 else
1727 return 0;
1728}
1729
1730GLsizei TextureD3D_3D::getDepth(GLint level) const
1731{
1732 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1733 return mImageArray[level]->getDepth();
1734 else
1735 return 0;
1736}
1737
1738GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1739{
1740 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1741 return mImageArray[level]->getInternalFormat();
1742 else
1743 return GL_NONE;
1744}
1745
1746bool TextureD3D_3D::isDepth(GLint level) const
1747{
Geoff Lang5d601382014-07-22 15:14:06 -04001748 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001749}
1750
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001751gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1752 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001753{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001754 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001755 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1756
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001757 redefineImage(level, sizedInternalFormat, size);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758
1759 bool fastUnpacked = false;
1760
Jamie Madillba6bc952014-10-06 10:56:22 -04001761 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1762
Brandon Jones78b1acd2014-07-15 15:33:07 -07001763 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1764 if (isFastUnpackable(unpack, sizedInternalFormat))
1765 {
1766 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001767 RenderTarget *destRenderTarget = NULL;
1768 gl::Error error = getRenderTarget(index, &destRenderTarget);
1769 if (error.isError())
1770 {
1771 return error;
1772 }
1773
Brandon Jones78b1acd2014-07-15 15:33:07 -07001774 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1775
Geoff Lang64f23f62014-09-10 14:40:12 -04001776 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1777 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001778 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001779 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001780 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001781
1782 // Ensure we don't overwrite our newly initialized data
1783 mImageArray[level]->markClean();
1784
1785 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001786 }
1787
1788 if (!fastUnpacked)
1789 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001790 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001791 if (error.isError())
1792 {
1793 return error;
1794 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001795 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001796
1797 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001798}
1799
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001800gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1801 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001803 ASSERT(target == GL_TEXTURE_3D);
1804
Brandon Jones78b1acd2014-07-15 15:33:07 -07001805 bool fastUnpacked = false;
1806
Jamie Madillac7579c2014-09-17 16:59:33 -04001807 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1808
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1810 if (isFastUnpackable(unpack, getInternalFormat(level)))
1811 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001812 RenderTarget *destRenderTarget = NULL;
1813 gl::Error error = getRenderTarget(index, &destRenderTarget);
1814 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001816 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001817 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001818
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001819 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -04001820 if (error.isError())
1821 {
1822 return error;
1823 }
1824
1825 // Ensure we don't overwrite our newly initialized data
1826 mImageArray[level]->markClean();
1827
1828 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001829 }
1830
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001831 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001832 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001833 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001834 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001835
1836 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001837}
1838
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001839gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1840 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001841{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001842 ASSERT(target == GL_TEXTURE_3D);
1843
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001844 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1845 redefineImage(level, internalFormat, size);
1846
1847 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1848 return TextureD3D::setCompressedImage(index, unpack, pixels);
1849}
1850
1851gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1852 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1853{
1854 ASSERT(target == GL_TEXTURE_3D);
1855
1856 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1857 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001858 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001859 {
Geoff Langb5348332014-09-02 13:16:34 -04001860 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861 }
Geoff Langb5348332014-09-02 13:16:34 -04001862
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001863 return commitRegion(index, area);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001864}
1865
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001866gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1867 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001868{
1869 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001870 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001871}
1872
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001873gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1874 const gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001875{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001876 ASSERT(target == GL_TEXTURE_3D);
1877
Jamie Madille76bdda2014-10-20 17:13:52 -04001878 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001879
Jamie Madille76bdda2014-10-20 17:13:52 -04001880 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001881 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001882 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001883 if (error.isError())
1884 {
1885 return error;
1886 }
1887
Brandon Jones78b1acd2014-07-15 15:33:07 -07001888 mDirtyImages = true;
1889 }
1890 else
1891 {
Geoff Langef7b0162014-09-04 13:29:23 -04001892 gl::Error error = ensureRenderTarget();
1893 if (error.isError())
1894 {
1895 return error;
1896 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001897
1898 if (isValidLevel(level))
1899 {
Geoff Langef7b0162014-09-04 13:29:23 -04001900 error = updateStorageLevel(level);
1901 if (error.isError())
1902 {
1903 return error;
1904 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001905
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001906 error = mRenderer->copyImage3D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -04001907 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001908 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001909 if (error.isError())
1910 {
1911 return error;
1912 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001913 }
1914 }
Geoff Langef7b0162014-09-04 13:29:23 -04001915
1916 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917}
1918
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001919gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001920{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001921 ASSERT(target == GL_TEXTURE_3D);
1922
Geoff Lang8fed1f72015-01-09 11:09:33 -05001923 for (size_t level = 0; level < levels; level++)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001924 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001925 gl::Extents levelSize(std::max(1, size.width >> level),
1926 std::max(1, size.height >> level),
1927 std::max(1, size.depth >> level));
1928 mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001929 }
1930
1931 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1932 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001933 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001934 }
1935
Geoff Lang1f8532b2014-09-05 09:46:13 -04001936 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001937 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001938 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001939
1940 gl::Error error = setCompleteTexStorage(storage);
1941 if (error.isError())
1942 {
1943 SafeDelete(storage);
1944 return error;
1945 }
1946
1947 mImmutable = true;
1948
1949 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001950}
1951
Brandon Jones6053a522014-07-25 16:22:09 -07001952void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001953{
Brandon Jones6053a522014-07-25 16:22:09 -07001954 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001955}
1956
Brandon Jones6053a522014-07-25 16:22:09 -07001957void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001958{
Brandon Jones6053a522014-07-25 16:22:09 -07001959 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001960}
1961
Brandon Jones6053a522014-07-25 16:22:09 -07001962
Jamie Madill4aa79e12014-09-29 10:46:14 -04001963void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001964{
1965 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1966 int levelCount = mipLevels();
1967 for (int level = 1; level < levelCount; level++)
1968 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001969 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
1970 std::max(getBaseLevelHeight() >> level, 1),
1971 std::max(getBaseLevelDepth() >> level, 1));
1972 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001973 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001974}
1975
Jamie Madillac7579c2014-09-17 16:59:33 -04001976unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001977{
Geoff Langef7b0162014-09-04 13:29:23 -04001978 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001979}
1980
Geoff Lang64f23f62014-09-10 14:40:12 -04001981gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001982{
1983 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001984 gl::Error error = ensureRenderTarget();
1985 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001986 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001987 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001988 }
1989
Jamie Madillac7579c2014-09-17 16:59:33 -04001990 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001991 {
Geoff Langef7b0162014-09-04 13:29:23 -04001992 error = updateStorage();
1993 if (error.isError())
1994 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001995 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001996 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001997 }
1998 else
1999 {
Geoff Langef7b0162014-09-04 13:29:23 -04002000 error = updateStorageLevel(index.mipIndex);
2001 if (error.isError())
2002 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002003 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002004 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002005 }
2006
Geoff Lang64f23f62014-09-10 14:40:12 -04002007 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002008}
2009
Geoff Langef7b0162014-09-04 13:29:23 -04002010gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002011{
2012 // Only initialize the first time this texture is used as a render target or shader resource
2013 if (mTexStorage)
2014 {
Geoff Langef7b0162014-09-04 13:29:23 -04002015 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002016 }
2017
2018 // do not attempt to create storage for nonexistant data
2019 if (!isLevelComplete(0))
2020 {
Geoff Langef7b0162014-09-04 13:29:23 -04002021 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002022 }
2023
2024 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2025
Jamie Madill30d6c252014-11-13 10:03:33 -05002026 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002027 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2028 if (error.isError())
2029 {
2030 return error;
2031 }
2032
2033 error = setCompleteTexStorage(storage);
2034 if (error.isError())
2035 {
2036 SafeDelete(storage);
2037 return error;
2038 }
2039
Brandon Jones78b1acd2014-07-15 15:33:07 -07002040 ASSERT(mTexStorage);
2041
2042 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002043 error = updateStorage();
2044 if (error.isError())
2045 {
2046 return error;
2047 }
2048
2049 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002050}
2051
Geoff Langef7b0162014-09-04 13:29:23 -04002052gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002053{
2054 GLsizei width = getBaseLevelWidth();
2055 GLsizei height = getBaseLevelHeight();
2056 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002057 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002058
2059 ASSERT(width > 0 && height > 0 && depth > 0);
2060
2061 // use existing storage level count, when previously specified by TexStorage*D
2062 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2063
Geoff Langef7b0162014-09-04 13:29:23 -04002064 // TODO: Verify creation of the storage succeeded
2065 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2066
2067 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002068}
2069
Geoff Langef7b0162014-09-04 13:29:23 -04002070gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002071{
2072 SafeDelete(mTexStorage);
2073 mTexStorage = newCompleteTexStorage;
2074 mDirtyImages = true;
2075
2076 // We do not support managed 3D storage, as that is D3D9/ES2-only
2077 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002078
2079 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002080}
2081
Geoff Langef7b0162014-09-04 13:29:23 -04002082gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002083{
2084 ASSERT(mTexStorage != NULL);
2085 GLint storageLevels = mTexStorage->getLevelCount();
2086 for (int level = 0; level < storageLevels; level++)
2087 {
2088 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2089 {
Geoff Langef7b0162014-09-04 13:29:23 -04002090 gl::Error error = updateStorageLevel(level);
2091 if (error.isError())
2092 {
2093 return error;
2094 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002095 }
2096 }
Geoff Langef7b0162014-09-04 13:29:23 -04002097
2098 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002099}
2100
Brandon Jones78b1acd2014-07-15 15:33:07 -07002101bool TextureD3D_3D::isValidLevel(int level) const
2102{
2103 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2104}
2105
2106bool TextureD3D_3D::isLevelComplete(int level) const
2107{
2108 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2109
2110 if (isImmutable())
2111 {
2112 return true;
2113 }
2114
2115 GLsizei width = getBaseLevelWidth();
2116 GLsizei height = getBaseLevelHeight();
2117 GLsizei depth = getBaseLevelDepth();
2118
2119 if (width <= 0 || height <= 0 || depth <= 0)
2120 {
2121 return false;
2122 }
2123
2124 if (level == 0)
2125 {
2126 return true;
2127 }
2128
2129 ImageD3D *levelImage = mImageArray[level];
2130
2131 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2132 {
2133 return false;
2134 }
2135
2136 if (levelImage->getWidth() != std::max(1, width >> level))
2137 {
2138 return false;
2139 }
2140
2141 if (levelImage->getHeight() != std::max(1, height >> level))
2142 {
2143 return false;
2144 }
2145
2146 if (levelImage->getDepth() != std::max(1, depth >> level))
2147 {
2148 return false;
2149 }
2150
2151 return true;
2152}
2153
Jamie Madille76bdda2014-10-20 17:13:52 -04002154bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2155{
2156 return isLevelComplete(index.mipIndex);
2157}
2158
Geoff Langef7b0162014-09-04 13:29:23 -04002159gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002160{
2161 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2162 ASSERT(isLevelComplete(level));
2163
2164 if (mImageArray[level]->isDirty())
2165 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002166 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2167 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002168 gl::Error error = commitRegion(index, region);
2169 if (error.isError())
2170 {
2171 return error;
2172 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002173 }
Geoff Langef7b0162014-09-04 13:29:23 -04002174
2175 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002176}
2177
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002178void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002179{
2180 // If there currently is a corresponding storage texture image, it has these parameters
2181 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2182 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2183 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2184 const GLenum storageFormat = getBaseLevelInternalFormat();
2185
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002186 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002187
2188 if (mTexStorage)
2189 {
2190 const int storageLevels = mTexStorage->getLevelCount();
2191
2192 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002193 size.width != storageWidth ||
2194 size.height != storageHeight ||
2195 size.depth != storageDepth ||
Brandon Jones78b1acd2014-07-15 15:33:07 -07002196 internalformat != storageFormat) // Discard mismatched storage
2197 {
2198 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2199 {
2200 mImageArray[i]->markDirty();
2201 }
2202
2203 SafeDelete(mTexStorage);
2204 mDirtyImages = true;
2205 }
2206 }
2207}
2208
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002209gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2210{
2211 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2212 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2213}
Brandon Jones142ec422014-07-16 10:31:30 -07002214
Jamie Madillcb83dc12014-09-29 10:46:12 -04002215gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2216{
2217 // The "layer" here does not apply to 3D images. We use one Image per mip.
2218 return gl::ImageIndex::Make3D(mip);
2219}
2220
Jamie Madill710e5772014-10-20 17:13:53 -04002221bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2222{
2223 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2224 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2225}
2226
Jamie Madill93e13fb2014-11-06 15:27:25 -05002227TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002228 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002229{
2230 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2231 {
2232 mLayerCounts[level] = 0;
2233 mImageArray[level] = NULL;
2234 }
2235}
2236
2237TextureD3D_2DArray::~TextureD3D_2DArray()
2238{
Austin Kinross69822602014-08-12 15:51:37 -07002239 // Delete the Images before the TextureStorage.
2240 // Images might be relying on the TextureStorage for some of their data.
2241 // 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 -07002242 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002243 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002244}
2245
Brandon Jones142ec422014-07-16 10:31:30 -07002246Image *TextureD3D_2DArray::getImage(int level, int layer) const
2247{
2248 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002249 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2250 layer < mLayerCounts[level]);
2251 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002252}
2253
Jamie Madillfeda4d22014-09-17 13:03:29 -04002254Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2255{
2256 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002257 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2258 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002259 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002260 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002261}
2262
Brandon Jones142ec422014-07-16 10:31:30 -07002263GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2264{
2265 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2266 return mLayerCounts[level];
2267}
2268
Brandon Jones142ec422014-07-16 10:31:30 -07002269GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2270{
2271 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2272}
2273
2274GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2275{
2276 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2277}
2278
Brandon Jones142ec422014-07-16 10:31:30 -07002279GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2280{
2281 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2282}
2283
2284bool TextureD3D_2DArray::isDepth(GLint level) const
2285{
Geoff Lang5d601382014-07-22 15:14:06 -04002286 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002287}
2288
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002289gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
2290 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002291{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002292 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2293
Geoff Lang5d601382014-07-22 15:14:06 -04002294 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2295
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002296 redefineImage(level, sizedInternalFormat, size);
Brandon Jones142ec422014-07-16 10:31:30 -07002297
Geoff Lang5d601382014-07-22 15:14:06 -04002298 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002299 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002300
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002301 for (int i = 0; i < size.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002302 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002303 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002304 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002305 gl::Error error = TextureD3D::setImage(index, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002306 if (error.isError())
2307 {
2308 return error;
2309 }
Brandon Jones142ec422014-07-16 10:31:30 -07002310 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002311
2312 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002313}
2314
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002315gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
2316 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002317{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002318 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2319
Geoff Lang5d601382014-07-22 15:14:06 -04002320 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002321 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002322
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002323 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002324 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002325 int layer = area.z + i;
2326 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2327
2328 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002329
Jamie Madillfeda4d22014-09-17 13:03:29 -04002330 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002331 gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002332 if (error.isError())
2333 {
2334 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002335 }
2336 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002337
2338 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002339}
2340
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002341gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
2342 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
2343{
2344 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2345
2346 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2347 redefineImage(level, internalFormat, size);
2348
2349 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2350 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1);
2351
2352 for (int i = 0; i < size.depth; i++)
2353 {
2354 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2355
2356 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2357 gl::Error error = TextureD3D::setCompressedImage(index, unpack, layerPixels);
2358 if (error.isError())
2359 {
2360 return error;
2361 }
2362 }
2363
2364 return gl::Error(GL_NO_ERROR);
2365}
2366
2367gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
2368 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002369{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002370 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2371
Geoff Lang5d601382014-07-22 15:14:06 -04002372 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002373 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002374
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002375 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002376 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002377 int layer = area.z + i;
2378 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Brandon Jones142ec422014-07-16 10:31:30 -07002379
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002380 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
2381
2382 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2383 gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, layerPixels);
Geoff Langb5348332014-09-02 13:16:34 -04002384 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002385 {
Geoff Langb5348332014-09-02 13:16:34 -04002386 return error;
2387 }
2388
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002389 error = commitRegion(index, layerArea);
Geoff Langb5348332014-09-02 13:16:34 -04002390 if (error.isError())
2391 {
2392 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002393 }
2394 }
Geoff Langb5348332014-09-02 13:16:34 -04002395
2396 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002397}
2398
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002399gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
2400 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002401{
2402 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002403 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002404}
2405
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002406gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
2407 const gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002408{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002409 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2410
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002411 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002412
Jamie Madille76bdda2014-10-20 17:13:52 -04002413 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002414 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002415 gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
2416 gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04002417 if (error.isError())
2418 {
2419 return error;
2420 }
2421
Brandon Jones142ec422014-07-16 10:31:30 -07002422 mDirtyImages = true;
2423 }
2424 else
2425 {
Geoff Langef7b0162014-09-04 13:29:23 -04002426 gl::Error error = ensureRenderTarget();
2427 if (error.isError())
2428 {
2429 return error;
2430 }
Brandon Jones142ec422014-07-16 10:31:30 -07002431
2432 if (isValidLevel(level))
2433 {
Geoff Langef7b0162014-09-04 13:29:23 -04002434 error = updateStorageLevel(level);
2435 if (error.isError())
2436 {
2437 return error;
2438 }
Brandon Jones142ec422014-07-16 10:31:30 -07002439
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002440 error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2441 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04002442 if (error.isError())
2443 {
2444 return error;
2445 }
Brandon Jones142ec422014-07-16 10:31:30 -07002446 }
2447 }
Geoff Langef7b0162014-09-04 13:29:23 -04002448 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002449}
2450
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002451gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002452{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002453 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2454
Brandon Jones142ec422014-07-16 10:31:30 -07002455 deleteImages();
2456
Geoff Lang8fed1f72015-01-09 11:09:33 -05002457 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
Brandon Jones142ec422014-07-16 10:31:30 -07002458 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002459 gl::Extents levelLayerSize(std::max(1, size.width >> level),
2460 std::max(1, size.height >> level),
2461 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002462
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002463 mLayerCounts[level] = (level < levels ? size.depth : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002464
2465 if (mLayerCounts[level] > 0)
2466 {
2467 // Create new images for this level
2468 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2469
2470 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2471 {
2472 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002473 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true);
Brandon Jones142ec422014-07-16 10:31:30 -07002474 }
2475 }
2476 }
2477
Geoff Lang1f8532b2014-09-05 09:46:13 -04002478 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002479 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002480 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002481
2482 gl::Error error = setCompleteTexStorage(storage);
2483 if (error.isError())
2484 {
2485 SafeDelete(storage);
2486 return error;
2487 }
2488
2489 mImmutable = true;
2490
2491 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002492}
2493
Brandon Jones6053a522014-07-25 16:22:09 -07002494void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002495{
Brandon Jones6053a522014-07-25 16:22:09 -07002496 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002497}
2498
Brandon Jones6053a522014-07-25 16:22:09 -07002499void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002500{
Brandon Jones6053a522014-07-25 16:22:09 -07002501 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002502}
2503
Brandon Jones6053a522014-07-25 16:22:09 -07002504
Jamie Madill4aa79e12014-09-29 10:46:14 -04002505void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002506{
2507 int baseWidth = getBaseLevelWidth();
2508 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002509 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002510 GLenum baseFormat = getBaseLevelInternalFormat();
2511
2512 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2513 int levelCount = mipLevels();
2514 for (int level = 1; level < levelCount; level++)
2515 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002516 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
2517 std::max(baseHeight >> level, 1),
2518 baseDepth);
2519 redefineImage(level, baseFormat, levelLayerSize);
Brandon Jones142ec422014-07-16 10:31:30 -07002520 }
Brandon Jones142ec422014-07-16 10:31:30 -07002521}
2522
Jamie Madillac7579c2014-09-17 16:59:33 -04002523unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002524{
Geoff Langef7b0162014-09-04 13:29:23 -04002525 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002526}
2527
Geoff Lang64f23f62014-09-10 14:40:12 -04002528gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002529{
2530 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002531 gl::Error error = ensureRenderTarget();
2532 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002533 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002534 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002535 }
2536
Geoff Langef7b0162014-09-04 13:29:23 -04002537 error = updateStorageLevel(index.mipIndex);
2538 if (error.isError())
2539 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002540 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002541 }
2542
Geoff Lang64f23f62014-09-10 14:40:12 -04002543 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002544}
2545
Geoff Langef7b0162014-09-04 13:29:23 -04002546gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002547{
2548 // Only initialize the first time this texture is used as a render target or shader resource
2549 if (mTexStorage)
2550 {
Geoff Langef7b0162014-09-04 13:29:23 -04002551 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002552 }
2553
2554 // do not attempt to create storage for nonexistant data
2555 if (!isLevelComplete(0))
2556 {
Geoff Langef7b0162014-09-04 13:29:23 -04002557 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002558 }
2559
2560 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2561
Geoff Langef7b0162014-09-04 13:29:23 -04002562 TextureStorage *storage = NULL;
2563 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2564 if (error.isError())
2565 {
2566 return error;
2567 }
2568
2569 error = setCompleteTexStorage(storage);
2570 if (error.isError())
2571 {
2572 SafeDelete(storage);
2573 return error;
2574 }
2575
Brandon Jones142ec422014-07-16 10:31:30 -07002576 ASSERT(mTexStorage);
2577
2578 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002579 error = updateStorage();
2580 if (error.isError())
2581 {
2582 return error;
2583 }
2584
2585 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002586}
2587
Geoff Langef7b0162014-09-04 13:29:23 -04002588gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002589{
2590 GLsizei width = getBaseLevelWidth();
2591 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002592 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002593 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002594
2595 ASSERT(width > 0 && height > 0 && depth > 0);
2596
2597 // use existing storage level count, when previously specified by TexStorage*D
2598 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2599
Geoff Langef7b0162014-09-04 13:29:23 -04002600 // TODO(geofflang): Verify storage creation succeeds
2601 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2602
2603 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002604}
2605
Geoff Langef7b0162014-09-04 13:29:23 -04002606gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002607{
2608 SafeDelete(mTexStorage);
2609 mTexStorage = newCompleteTexStorage;
2610 mDirtyImages = true;
2611
2612 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2613 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002614
2615 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002616}
2617
Geoff Langef7b0162014-09-04 13:29:23 -04002618gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002619{
2620 ASSERT(mTexStorage != NULL);
2621 GLint storageLevels = mTexStorage->getLevelCount();
2622 for (int level = 0; level < storageLevels; level++)
2623 {
2624 if (isLevelComplete(level))
2625 {
Geoff Langef7b0162014-09-04 13:29:23 -04002626 gl::Error error = updateStorageLevel(level);
2627 if (error.isError())
2628 {
2629 return error;
2630 }
Brandon Jones142ec422014-07-16 10:31:30 -07002631 }
2632 }
Geoff Langef7b0162014-09-04 13:29:23 -04002633
2634 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002635}
2636
Brandon Jones142ec422014-07-16 10:31:30 -07002637bool TextureD3D_2DArray::isValidLevel(int level) const
2638{
2639 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2640}
2641
2642bool TextureD3D_2DArray::isLevelComplete(int level) const
2643{
2644 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2645
2646 if (isImmutable())
2647 {
2648 return true;
2649 }
2650
2651 GLsizei width = getBaseLevelWidth();
2652 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002653 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002654
2655 if (width <= 0 || height <= 0 || layers <= 0)
2656 {
2657 return false;
2658 }
2659
2660 if (level == 0)
2661 {
2662 return true;
2663 }
2664
2665 if (getInternalFormat(level) != getInternalFormat(0))
2666 {
2667 return false;
2668 }
2669
2670 if (getWidth(level) != std::max(1, width >> level))
2671 {
2672 return false;
2673 }
2674
2675 if (getHeight(level) != std::max(1, height >> level))
2676 {
2677 return false;
2678 }
2679
Jamie Madill3269bcb2014-09-30 16:33:52 -04002680 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002681 {
2682 return false;
2683 }
2684
2685 return true;
2686}
2687
Jamie Madille76bdda2014-10-20 17:13:52 -04002688bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2689{
2690 return isLevelComplete(index.mipIndex);
2691}
2692
Geoff Langef7b0162014-09-04 13:29:23 -04002693gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002694{
2695 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2696 ASSERT(isLevelComplete(level));
2697
2698 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2699 {
2700 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2701 if (mImageArray[level][layer]->isDirty())
2702 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002703 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2704 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002705 gl::Error error = commitRegion(index, region);
2706 if (error.isError())
2707 {
2708 return error;
2709 }
Brandon Jones142ec422014-07-16 10:31:30 -07002710 }
2711 }
Geoff Langef7b0162014-09-04 13:29:23 -04002712
2713 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002714}
2715
2716void TextureD3D_2DArray::deleteImages()
2717{
2718 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2719 {
2720 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2721 {
2722 delete mImageArray[level][layer];
2723 }
2724 delete[] mImageArray[level];
2725 mImageArray[level] = NULL;
2726 mLayerCounts[level] = 0;
2727 }
2728}
2729
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002730void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002731{
2732 // If there currently is a corresponding storage texture image, it has these parameters
2733 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2734 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002735 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002736 const GLenum storageFormat = getBaseLevelInternalFormat();
2737
2738 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2739 {
2740 delete mImageArray[level][layer];
2741 }
2742 delete[] mImageArray[level];
2743 mImageArray[level] = NULL;
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002744 mLayerCounts[level] = size.depth;
Brandon Jones142ec422014-07-16 10:31:30 -07002745
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002746 if (size.depth > 0)
Brandon Jones142ec422014-07-16 10:31:30 -07002747 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002748 mImageArray[level] = new ImageD3D*[size.depth]();
Brandon Jones142ec422014-07-16 10:31:30 -07002749
2750 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2751 {
2752 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002753 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
2754 gl::Extents(size.width, size.height, 1), false);
Brandon Jones142ec422014-07-16 10:31:30 -07002755 }
2756 }
2757
2758 if (mTexStorage)
2759 {
2760 const int storageLevels = mTexStorage->getLevelCount();
2761
2762 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002763 size.width != storageWidth ||
2764 size.height != storageHeight ||
2765 size.depth != storageDepth ||
Brandon Jones142ec422014-07-16 10:31:30 -07002766 internalformat != storageFormat) // Discard mismatched storage
2767 {
2768 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2769 {
2770 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2771 {
2772 mImageArray[level][layer]->markDirty();
2773 }
2774 }
2775
2776 delete mTexStorage;
2777 mTexStorage = NULL;
2778 mDirtyImages = true;
2779 }
2780 }
2781}
2782
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002783gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2784{
2785 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2786}
2787
Jamie Madillcb83dc12014-09-29 10:46:12 -04002788gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2789{
2790 return gl::ImageIndex::Make2DArray(mip, layer);
2791}
2792
Jamie Madill710e5772014-10-20 17:13:53 -04002793bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2794{
2795 // Check for having a storage and the right type of index
2796 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2797 {
2798 return false;
2799 }
2800
2801 // Check the mip index
2802 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2803 {
2804 return false;
2805 }
2806
2807 // Check the layer index
2808 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2809}
2810
Brandon Jones78b1acd2014-07-15 15:33:07 -07002811}