blob: 09d4c84c7964c6fe2ea013f4a6c477a3f90d8a8d [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
Austin Kinross215b37a2014-12-22 12:56:07 -0800358 if (mTexStorage && mRenderer->getWorkarounds().zeroMaxLodWorkaround)
359 {
360 // Switch to using the mipmapped texture.
361 gl::Error error = getNativeTexture()->useLevelZeroWorkaroundTexture(false);
362 if (error.isError())
363 {
364 return error;
365 }
366 }
367
Jamie Madill4aa79e12014-09-29 10:46:14 -0400368 // We know that all layers have the same dimension, for the texture to be complete
369 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400370
Jamie Madill9aca0592014-10-06 16:26:59 -0400371 // When making mipmaps with the setData workaround enabled, the texture storage has
372 // the image data already. For non-render-target storage, we have to pull it out into
373 // an image layer.
374 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
375 {
376 if (!mTexStorage->isRenderTarget())
377 {
378 // Copy from the storage mip 0 to Image mip 0
379 for (GLint layer = 0; layer < layerCount; ++layer)
380 {
381 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400382
Jamie Madill9aca0592014-10-06 16:26:59 -0400383 Image *image = getImage(srcIndex);
384 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500385 gl::Offset offset(0, 0, 0);
386 gl::Error error = image->copy(offset, area, srcIndex, mTexStorage);
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400387 if (error.isError())
388 {
389 return error;
390 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400391 }
392 }
393 else
394 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400395 gl::Error error = updateStorage();
396 if (error.isError())
397 {
398 return error;
399 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400400 }
401 }
402
Austin Kinross215b37a2014-12-22 12:56:07 -0800403 // TODO: Decouple this from zeroMaxLodWorkaround. This is a 9_3 restriction, unrelated to zeroMaxLodWorkaround.
404 // The restriction is because Feature Level 9_3 can't create SRVs on individual levels of the texture.
405 // As a result, even if the storage is a rendertarget, we can't use the GPU to generate the mipmaps without further work.
406 // The D3D9 renderer works around this by copying each level of the texture into its own single-layer GPU texture (in Blit9::boxFilter).
407 // Feature Level 9_3 could do something similar, or it could continue to use CPU-side mipmap generation, or something else.
408 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget() && !(mRenderer->getWorkarounds().zeroMaxLodWorkaround));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400409
410 for (GLint layer = 0; layer < layerCount; ++layer)
411 {
412 for (GLint mip = 1; mip < mipCount; ++mip)
413 {
414 ASSERT(getLayerCount(mip) == layerCount);
415
416 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
417 gl::ImageIndex destIndex = getImageIndex(mip, layer);
418
419 if (renderableStorage)
420 {
421 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400422 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
423 if (error.isError())
424 {
425 return error;
426 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400427 }
428 else
429 {
430 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400431 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
432 if (error.isError())
433 {
434 return error;
435 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400436 }
437 }
438 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400439
440 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400441}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700442
Jamie Madill135570a2014-09-30 16:33:51 -0400443bool TextureD3D::isBaseImageZeroSize() const
444{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400445 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400446
447 if (!baseImage || baseImage->getWidth() <= 0)
448 {
449 return true;
450 }
451
Geoff Lang691e58c2014-12-19 17:03:25 -0500452 if (!gl::IsCubeMapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
Jamie Madill135570a2014-09-30 16:33:51 -0400453 {
454 return true;
455 }
456
457 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
458 {
459 return true;
460 }
461
462 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
463 {
464 return true;
465 }
466
467 return false;
468}
469
Geoff Langef7b0162014-09-04 13:29:23 -0400470gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400471{
Geoff Langef7b0162014-09-04 13:29:23 -0400472 gl::Error error = initializeStorage(true);
473 if (error.isError())
474 {
475 return error;
476 }
Jamie Madill135570a2014-09-30 16:33:51 -0400477
478 if (!isBaseImageZeroSize())
479 {
480 ASSERT(mTexStorage);
481 if (!mTexStorage->isRenderTarget())
482 {
Geoff Langef7b0162014-09-04 13:29:23 -0400483 TextureStorage *newRenderTargetStorage = NULL;
484 error = createCompleteStorage(true, &newRenderTargetStorage);
485 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400486 {
Geoff Langef7b0162014-09-04 13:29:23 -0400487 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400488 }
489
Geoff Langef7b0162014-09-04 13:29:23 -0400490 error = mTexStorage->copyToStorage(newRenderTargetStorage);
491 if (error.isError())
492 {
493 SafeDelete(newRenderTargetStorage);
494 return error;
495 }
496
497 error = setCompleteTexStorage(newRenderTargetStorage);
498 if (error.isError())
499 {
500 SafeDelete(newRenderTargetStorage);
501 return error;
502 }
Jamie Madill135570a2014-09-30 16:33:51 -0400503 }
504 }
505
Geoff Langef7b0162014-09-04 13:29:23 -0400506 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400507}
508
Jamie Madille76bdda2014-10-20 17:13:52 -0400509bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
510{
Jamie Madill30d6c252014-11-13 10:03:33 -0500511 Image *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400512 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
513 return (image->isRenderableFormat() && levelsComplete);
514}
515
Jamie Madill710e5772014-10-20 17:13:53 -0400516gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
517{
518 if (mTexStorage)
519 {
520 ASSERT(isValidIndex(index));
521 Image *image = getImage(index);
522 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
523 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
524 if (error.isError())
525 {
526 return error;
527 }
528
529 image->markClean();
530 }
531
532 return gl::Error(GL_NO_ERROR);
533}
534
Jamie Madill93e13fb2014-11-06 15:27:25 -0500535TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400536 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700537{
538 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
539 {
540 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
541 }
542}
543
544TextureD3D_2D::~TextureD3D_2D()
545{
Austin Kinross69822602014-08-12 15:51:37 -0700546 // Delete the Images before the TextureStorage.
547 // Images might be relying on the TextureStorage for some of their data.
548 // 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 -0700549 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
550 {
551 delete mImageArray[i];
552 }
Austin Kinross69822602014-08-12 15:51:37 -0700553
554 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555}
556
Brandon Jonescef06ff2014-08-05 13:27:48 -0700557Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700558{
559 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700560 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700561 return mImageArray[level];
562}
563
Jamie Madillfeda4d22014-09-17 13:03:29 -0400564Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
565{
566 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400567 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400568 ASSERT(index.type == GL_TEXTURE_2D);
569 return mImageArray[index.mipIndex];
570}
571
Brandon Jonescef06ff2014-08-05 13:27:48 -0700572GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700573{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700574 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
575 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700576}
577
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700578GLsizei TextureD3D_2D::getWidth(GLint level) const
579{
580 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
581 return mImageArray[level]->getWidth();
582 else
583 return 0;
584}
585
586GLsizei TextureD3D_2D::getHeight(GLint level) const
587{
588 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
589 return mImageArray[level]->getHeight();
590 else
591 return 0;
592}
593
594GLenum TextureD3D_2D::getInternalFormat(GLint level) const
595{
596 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
597 return mImageArray[level]->getInternalFormat();
598 else
599 return GL_NONE;
600}
601
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700602bool TextureD3D_2D::isDepth(GLint level) const
603{
Geoff Lang5d601382014-07-22 15:14:06 -0400604 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700605}
606
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500607gl::Error TextureD3D_2D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
608 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700609{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500610 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700611
Geoff Lang5d601382014-07-22 15:14:06 -0400612 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
613
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700614 bool fastUnpacked = false;
615
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500616 redefineImage(level, sizedInternalFormat, size);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700617
Jamie Madillba6bc952014-10-06 10:56:22 -0400618 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
619
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700620 // Attempt a fast gpu copy of the pixel data to the surface
621 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
622 {
623 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400624 RenderTarget *destRenderTarget = NULL;
625 gl::Error error = getRenderTarget(index, &destRenderTarget);
626 if (error.isError())
627 {
628 return error;
629 }
630
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
632
Geoff Lang64f23f62014-09-10 14:40:12 -0400633 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
634 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700635 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400636 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700637 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400638
639 // Ensure we don't overwrite our newly initialized data
640 mImageArray[level]->markClean();
641
642 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643 }
644
645 if (!fastUnpacked)
646 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500647 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400648 if (error.isError())
649 {
650 return error;
651 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700652 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400653
654 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700655}
656
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500657gl::Error TextureD3D_2D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
658 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700659{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500660 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700661
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700662 bool fastUnpacked = false;
663
Jamie Madillac7579c2014-09-17 16:59:33 -0400664 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700665 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
666 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400667 RenderTarget *renderTarget = NULL;
668 gl::Error error = getRenderTarget(index, &renderTarget);
669 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700670 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400671 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400673
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500674 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, renderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -0400675 if (error.isError())
676 {
677 return error;
678 }
679
680 // Ensure we don't overwrite our newly initialized data
681 mImageArray[level]->markClean();
682
683 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700684 }
685
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400686 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700687 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500688 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700689 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400690
691 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700692}
693
Brandon Jonescef06ff2014-08-05 13:27:48 -0700694
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500695gl::Error TextureD3D_2D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
696 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
697{
698 ASSERT(target == GL_TEXTURE_2D && size.depth == 1);
699
700 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
701 redefineImage(level, internalFormat, size);
702
703 return TextureD3D::setCompressedImage(gl::ImageIndex::Make2D(level), unpack, pixels);
704}
705
706gl::Error TextureD3D_2D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
707 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
708{
709 ASSERT(target == GL_TEXTURE_2D && area.depth == 1 && area.z == 0);
710
711 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
712 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -0400713 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700714 {
Geoff Langb5348332014-09-02 13:16:34 -0400715 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700716 }
Geoff Langb5348332014-09-02 13:16:34 -0400717
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500718 return commitRegion(index, area);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700719}
720
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500721gl::Error TextureD3D_2D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
722 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700723{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700724 ASSERT(target == GL_TEXTURE_2D);
725
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500726 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
727 redefineImage(level, sizedInternalFormat, gl::Extents(sourceArea.width, sourceArea.height, 1));
Brandon Jonescef06ff2014-08-05 13:27:48 -0700728
Jamie Madille76bdda2014-10-20 17:13:52 -0400729 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500730 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400731
Jamie Madille76bdda2014-10-20 17:13:52 -0400732 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500734 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400735 if (error.isError())
736 {
737 return error;
738 }
739
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700740 mDirtyImages = true;
741 }
742 else
743 {
Geoff Langef7b0162014-09-04 13:29:23 -0400744 gl::Error error = ensureRenderTarget();
745 if (error.isError())
746 {
747 return error;
748 }
749
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700750 mImageArray[level]->markClean();
751
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500752 if (sourceArea.width != 0 && sourceArea.height != 0 && isValidLevel(level))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700753 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500754 gl::Error error = mRenderer->copyImage2D(source, sourceArea, internalFormat, destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400755 if (error.isError())
756 {
757 return error;
758 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700759 }
760 }
Geoff Langef7b0162014-09-04 13:29:23 -0400761
762 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700763}
764
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500765gl::Error TextureD3D_2D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
766 const gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700767{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500768 ASSERT(target == GL_TEXTURE_2D && destOffset.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700769
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
771 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700772
Jamie Madille76bdda2014-10-20 17:13:52 -0400773 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400774
Jamie Madille76bdda2014-10-20 17:13:52 -0400775 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700776 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500777 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -0400778 if (error.isError())
779 {
780 return error;
781 }
782
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700783 mDirtyImages = true;
784 }
785 else
786 {
Geoff Langef7b0162014-09-04 13:29:23 -0400787 gl::Error error = ensureRenderTarget();
788 if (error.isError())
789 {
790 return error;
791 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700792
793 if (isValidLevel(level))
794 {
Geoff Langef7b0162014-09-04 13:29:23 -0400795 error = updateStorageLevel(level);
796 if (error.isError())
797 {
798 return error;
799 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700800
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500801 error = mRenderer->copyImage2D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -0400802 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500803 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -0400804 if (error.isError())
805 {
806 return error;
807 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700808 }
809 }
Geoff Langef7b0162014-09-04 13:29:23 -0400810
811 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812}
813
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500814gl::Error TextureD3D_2D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700815{
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500816 ASSERT(GL_TEXTURE_2D && size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700817
Geoff Lang8fed1f72015-01-09 11:09:33 -0500818 for (size_t level = 0; level < levels; level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700819 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500820 gl::Extents levelSize(std::max(1, size.width >> level),
821 std::max(1, size.height >> level),
822 1);
823 mImageArray[level]->redefine(GL_TEXTURE_2D, internalFormat, levelSize, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700824 }
825
826 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
827 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500828 mImageArray[level]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700829 }
830
Geoff Lang1f8532b2014-09-05 09:46:13 -0400831 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400832 bool renderTarget = IsRenderTargetUsage(mUsage);
Austin Kinross215b37a2014-12-22 12:56:07 -0800833 TextureStorage *storage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, size.width, size.height, levels, false);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400834
835 gl::Error error = setCompleteTexStorage(storage);
836 if (error.isError())
837 {
838 SafeDelete(storage);
839 return error;
840 }
841
842 mImmutable = true;
843
844 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700845}
846
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700847void TextureD3D_2D::bindTexImage(egl::Surface *surface)
848{
849 GLenum internalformat = surface->getFormat();
850
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500851 gl::Extents size(surface->getWidth(), surface->getHeight(), 1);
852 mImageArray[0]->redefine(GL_TEXTURE_2D, internalformat, size, true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700853
854 if (mTexStorage)
855 {
856 SafeDelete(mTexStorage);
857 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400858
Jamie Madillfb0580a2014-11-27 14:03:52 -0500859 SurfaceD3D *surfaceD3D = SurfaceD3D::makeSurfaceD3D(surface);
860 ASSERT(surfaceD3D);
861
862 mTexStorage = mRenderer->createTextureStorage2D(surfaceD3D->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863
864 mDirtyImages = true;
865}
866
867void TextureD3D_2D::releaseTexImage()
868{
869 if (mTexStorage)
870 {
871 SafeDelete(mTexStorage);
872 }
873
874 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
875 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500876 mImageArray[i]->redefine(GL_TEXTURE_2D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700877 }
878}
879
Jamie Madill4aa79e12014-09-29 10:46:14 -0400880void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700881{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700882 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700883 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700884 for (int level = 1; level < levelCount; level++)
885 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -0500886 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
887 std::max(getBaseLevelHeight() >> level, 1),
888 1);
889
890 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700891 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700892}
893
Jamie Madillac7579c2014-09-17 16:59:33 -0400894unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700895{
Jamie Madillac7579c2014-09-17 16:59:33 -0400896 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400897 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700898}
899
Geoff Lang64f23f62014-09-10 14:40:12 -0400900gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700901{
Jamie Madillac7579c2014-09-17 16:59:33 -0400902 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700903
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700904 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400905 gl::Error error = ensureRenderTarget();
906 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700907 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400908 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700909 }
910
Geoff Langef7b0162014-09-04 13:29:23 -0400911 error = updateStorageLevel(index.mipIndex);
912 if (error.isError())
913 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400914 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400915 }
916
Geoff Lang64f23f62014-09-10 14:40:12 -0400917 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700918}
919
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700920bool TextureD3D_2D::isValidLevel(int level) const
921{
922 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
923}
924
925bool TextureD3D_2D::isLevelComplete(int level) const
926{
927 if (isImmutable())
928 {
929 return true;
930 }
931
Brandon Jones78b1acd2014-07-15 15:33:07 -0700932 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700933
934 GLsizei width = baseImage->getWidth();
935 GLsizei height = baseImage->getHeight();
936
937 if (width <= 0 || height <= 0)
938 {
939 return false;
940 }
941
942 // The base image level is complete if the width and height are positive
943 if (level == 0)
944 {
945 return true;
946 }
947
948 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700949 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700950
951 if (image->getInternalFormat() != baseImage->getInternalFormat())
952 {
953 return false;
954 }
955
956 if (image->getWidth() != std::max(1, width >> level))
957 {
958 return false;
959 }
960
961 if (image->getHeight() != std::max(1, height >> level))
962 {
963 return false;
964 }
965
966 return true;
967}
968
Jamie Madille76bdda2014-10-20 17:13:52 -0400969bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
970{
971 return isLevelComplete(index.mipIndex);
972}
973
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700974// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400975gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700976{
977 // Only initialize the first time this texture is used as a render target or shader resource
978 if (mTexStorage)
979 {
Geoff Langef7b0162014-09-04 13:29:23 -0400980 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700981 }
982
983 // do not attempt to create storage for nonexistant data
984 if (!isLevelComplete(0))
985 {
Geoff Langef7b0162014-09-04 13:29:23 -0400986 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700987 }
988
989 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
990
Geoff Langef7b0162014-09-04 13:29:23 -0400991 TextureStorage *storage = NULL;
992 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
993 if (error.isError())
994 {
995 return error;
996 }
997
998 error = setCompleteTexStorage(storage);
999 if (error.isError())
1000 {
1001 SafeDelete(storage);
1002 return error;
1003 }
1004
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001005 ASSERT(mTexStorage);
1006
1007 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001008 error = updateStorage();
1009 if (error.isError())
1010 {
1011 return error;
1012 }
1013
1014 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001015}
1016
Geoff Langef7b0162014-09-04 13:29:23 -04001017gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001018{
1019 GLsizei width = getBaseLevelWidth();
1020 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001021 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001022
1023 ASSERT(width > 0 && height > 0);
1024
1025 // use existing storage level count, when previously specified by TexStorage*D
1026 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1027
Austin Kinross215b37a2014-12-22 12:56:07 -08001028 bool hintLevelZeroOnly = false;
1029 if (mRenderer->getWorkarounds().zeroMaxLodWorkaround)
1030 {
1031 // If any of the CPU images (levels >= 1) are dirty, then the textureStorage2D should use the mipped texture to begin with.
1032 // Otherwise, it should use the level-zero-only texture.
1033 hintLevelZeroOnly = true;
1034 int level = 1;
1035 while (hintLevelZeroOnly && level < levels)
1036 {
1037 hintLevelZeroOnly = !(mImageArray[level]->isDirty() && isLevelComplete(level));
1038 level += 1;
1039 }
1040 }
1041
Geoff Langef7b0162014-09-04 13:29:23 -04001042 // TODO(geofflang): Determine if the texture creation succeeded
Austin Kinross215b37a2014-12-22 12:56:07 -08001043 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels, hintLevelZeroOnly);
Geoff Langef7b0162014-09-04 13:29:23 -04001044
1045 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001046}
1047
Geoff Langef7b0162014-09-04 13:29:23 -04001048gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001049{
Geoff Langef7b0162014-09-04 13:29:23 -04001050 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001051 {
Geoff Langef7b0162014-09-04 13:29:23 -04001052 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001053 {
Geoff Langef7b0162014-09-04 13:29:23 -04001054 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1055 if (error.isError())
1056 {
1057 return error;
1058 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001059 }
1060 }
1061
Geoff Langef7b0162014-09-04 13:29:23 -04001062 SafeDelete(mTexStorage);
1063 mTexStorage = newCompleteTexStorage;
1064
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001065 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001066
1067 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001068}
1069
Geoff Langef7b0162014-09-04 13:29:23 -04001070gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001071{
1072 ASSERT(mTexStorage != NULL);
1073 GLint storageLevels = mTexStorage->getLevelCount();
1074 for (int level = 0; level < storageLevels; level++)
1075 {
1076 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1077 {
Geoff Langef7b0162014-09-04 13:29:23 -04001078 gl::Error error = updateStorageLevel(level);
1079 if (error.isError())
1080 {
1081 return error;
1082 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001083 }
1084 }
Geoff Langef7b0162014-09-04 13:29:23 -04001085
1086 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001087}
1088
Geoff Langef7b0162014-09-04 13:29:23 -04001089gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001090{
1091 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1092 ASSERT(isLevelComplete(level));
1093
1094 if (mImageArray[level]->isDirty())
1095 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001096 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1097 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001098 gl::Error error = commitRegion(index, region);
1099 if (error.isError())
1100 {
1101 return error;
1102 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001103 }
Geoff Langef7b0162014-09-04 13:29:23 -04001104
1105 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001106}
1107
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001108void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001109{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001110 ASSERT(size.depth == 1);
1111
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001112 // If there currently is a corresponding storage texture image, it has these parameters
1113 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1114 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1115 const GLenum storageFormat = getBaseLevelInternalFormat();
1116
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001117 mImageArray[level]->redefine(GL_TEXTURE_2D, internalformat, size, false);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001118
1119 if (mTexStorage)
1120 {
1121 const int storageLevels = mTexStorage->getLevelCount();
1122
1123 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001124 size.width != storageWidth ||
1125 size.height != storageHeight ||
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001126 internalformat != storageFormat) // Discard mismatched storage
1127 {
1128 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1129 {
1130 mImageArray[i]->markDirty();
1131 }
1132
1133 SafeDelete(mTexStorage);
1134 mDirtyImages = true;
1135 }
1136 }
1137}
1138
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001139gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1140{
1141 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1142}
Brandon Jones0511e802014-07-14 16:27:26 -07001143
Jamie Madillcb83dc12014-09-29 10:46:12 -04001144gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1145{
1146 // "layer" does not apply to 2D Textures.
1147 return gl::ImageIndex::Make2D(mip);
1148}
1149
Jamie Madill710e5772014-10-20 17:13:53 -04001150bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1151{
1152 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1153 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1154}
1155
Jamie Madill93e13fb2014-11-06 15:27:25 -05001156TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001157 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001158{
1159 for (int i = 0; i < 6; i++)
1160 {
1161 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1162 {
1163 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1164 }
1165 }
1166}
1167
1168TextureD3D_Cube::~TextureD3D_Cube()
1169{
Austin Kinross69822602014-08-12 15:51:37 -07001170 // Delete the Images before the TextureStorage.
1171 // Images might be relying on the TextureStorage for some of their data.
1172 // 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 -07001173 for (int i = 0; i < 6; i++)
1174 {
1175 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1176 {
1177 SafeDelete(mImageArray[i][j]);
1178 }
1179 }
Austin Kinross69822602014-08-12 15:51:37 -07001180
1181 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001182}
1183
Brandon Jonescef06ff2014-08-05 13:27:48 -07001184Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001185{
1186 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001187 ASSERT(layer >= 0 && layer < 6);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001188 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001189}
1190
Jamie Madillfeda4d22014-09-17 13:03:29 -04001191Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1192{
1193 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madilleb32a2e2014-12-10 14:27:53 -05001194 ASSERT(index.layerIndex >= 0 && index.layerIndex < 6);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001195 return mImageArray[index.layerIndex][index.mipIndex];
1196}
1197
Brandon Jonescef06ff2014-08-05 13:27:48 -07001198GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001199{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001200 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1201 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001202}
1203
Brandon Jonescef06ff2014-08-05 13:27:48 -07001204GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001205{
1206 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001207 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001208 else
1209 return GL_NONE;
1210}
1211
Brandon Jonescef06ff2014-08-05 13:27:48 -07001212bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001213{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001214 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001215}
1216
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001217gl::Error TextureD3D_Cube::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1218 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001219{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001220 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001221
Geoff Lang5d601382014-07-22 15:14:06 -04001222 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001223 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001224
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001225 redefineImage(index.layerIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001226
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001227 return TextureD3D::setImage(index, type, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001228}
1229
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001230gl::Error TextureD3D_Cube::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1231 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001232{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001233 ASSERT(area.depth == 1 && area.z == 0);
1234
1235 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
1236 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
1237}
1238
1239gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1240 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1241{
1242 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001243
Brandon Jones0511e802014-07-14 16:27:26 -07001244 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Geoff Lang691e58c2014-12-19 17:03:25 -05001245 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001246
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001247 redefineImage(faceIndex, level, internalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001248
Jamie Madillfeda4d22014-09-17 13:03:29 -04001249 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001250 return TextureD3D::setCompressedImage(index, unpack, pixels);
Brandon Jones0511e802014-07-14 16:27:26 -07001251}
1252
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001253gl::Error TextureD3D_Cube::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1254 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001255{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001256 ASSERT(area.depth == 1 && area.z == 0);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001257
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001258 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001259
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001260 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001261 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001262 {
Geoff Langb5348332014-09-02 13:16:34 -04001263 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001264 }
Geoff Langb5348332014-09-02 13:16:34 -04001265
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001266 return commitRegion(index, area);
Brandon Jones0511e802014-07-14 16:27:26 -07001267}
1268
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001269gl::Error TextureD3D_Cube::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1270 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001271{
Geoff Lang691e58c2014-12-19 17:03:25 -05001272 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001273 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE);
Geoff Lang5d601382014-07-22 15:14:06 -04001274
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001275 gl::Extents size(sourceArea.width, sourceArea.height, 1);
1276 redefineImage(faceIndex, level, sizedInternalFormat, size);
Brandon Jones0511e802014-07-14 16:27:26 -07001277
Jamie Madille76bdda2014-10-20 17:13:52 -04001278 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001279 gl::Offset destOffset(0, 0, 0);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001280
Jamie Madille76bdda2014-10-20 17:13:52 -04001281 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001282 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001283 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001284 if (error.isError())
1285 {
1286 return error;
1287 }
1288
Brandon Jones0511e802014-07-14 16:27:26 -07001289 mDirtyImages = true;
1290 }
1291 else
1292 {
Geoff Langef7b0162014-09-04 13:29:23 -04001293 gl::Error error = ensureRenderTarget();
1294 if (error.isError())
1295 {
1296 return error;
1297 }
1298
Brandon Jones0511e802014-07-14 16:27:26 -07001299 mImageArray[faceIndex][level]->markClean();
1300
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001301 ASSERT(size.width == size.height);
Brandon Jones0511e802014-07-14 16:27:26 -07001302
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001303 if (size.width > 0 && isValidFaceLevel(faceIndex, level))
Brandon Jones0511e802014-07-14 16:27:26 -07001304 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001305 error = mRenderer->copyImageCube(source, sourceArea, internalFormat, destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001306 if (error.isError())
1307 {
1308 return error;
1309 }
Brandon Jones0511e802014-07-14 16:27:26 -07001310 }
1311 }
Geoff Langef7b0162014-09-04 13:29:23 -04001312
1313 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001314}
1315
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001316gl::Error TextureD3D_Cube::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1317 const gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001318{
Geoff Lang691e58c2014-12-19 17:03:25 -05001319 size_t faceIndex = gl::CubeMapTextureTargetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001320
Jamie Madille76bdda2014-10-20 17:13:52 -04001321 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001322
Jamie Madille76bdda2014-10-20 17:13:52 -04001323 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001324 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001325 gl::Error error = mImageArray[faceIndex][level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001326 if (error.isError())
1327 {
1328 return error;
1329 }
1330
Brandon Jones0511e802014-07-14 16:27:26 -07001331 mDirtyImages = true;
1332 }
1333 else
1334 {
Geoff Langef7b0162014-09-04 13:29:23 -04001335 gl::Error error = ensureRenderTarget();
1336 if (error.isError())
1337 {
1338 return error;
1339 }
Brandon Jones0511e802014-07-14 16:27:26 -07001340
1341 if (isValidFaceLevel(faceIndex, level))
1342 {
Geoff Langef7b0162014-09-04 13:29:23 -04001343 error = updateStorageFaceLevel(faceIndex, level);
1344 if (error.isError())
1345 {
1346 return error;
1347 }
Brandon Jones0511e802014-07-14 16:27:26 -07001348
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001349 error = mRenderer->copyImageCube(source, sourceArea, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1350 destOffset, mTexStorage, target, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001351 if (error.isError())
1352 {
1353 return error;
1354 }
Brandon Jones0511e802014-07-14 16:27:26 -07001355 }
1356 }
Geoff Langef7b0162014-09-04 13:29:23 -04001357
1358 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001359}
1360
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001361gl::Error TextureD3D_Cube::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001362{
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001363 ASSERT(size.width == size.height);
1364 ASSERT(size.depth == 1);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001365
Geoff Lang8fed1f72015-01-09 11:09:33 -05001366 for (size_t level = 0; level < levels; level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001367 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001368 GLsizei mipSize = std::max(1, size.width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001369 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1370 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001371 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalFormat, gl::Extents(mipSize, mipSize, 1), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001372 }
1373 }
1374
1375 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1376 {
1377 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1378 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001379 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones0511e802014-07-14 16:27:26 -07001380 }
1381 }
1382
Geoff Lang1f8532b2014-09-05 09:46:13 -04001383 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001384 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001385 TextureStorage *storage = mRenderer->createTextureStorageCube(internalFormat, renderTarget, size.width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001386
1387 gl::Error error = setCompleteTexStorage(storage);
1388 if (error.isError())
1389 {
1390 SafeDelete(storage);
1391 return error;
1392 }
1393
1394 mImmutable = true;
1395
1396 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001397}
1398
Brandon Jones0511e802014-07-14 16:27:26 -07001399// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1400bool TextureD3D_Cube::isCubeComplete() const
1401{
1402 int baseWidth = getBaseLevelWidth();
1403 int baseHeight = getBaseLevelHeight();
1404 GLenum baseFormat = getBaseLevelInternalFormat();
1405
1406 if (baseWidth <= 0 || baseWidth != baseHeight)
1407 {
1408 return false;
1409 }
1410
1411 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1412 {
1413 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1414
1415 if (faceBaseImage.getWidth() != baseWidth ||
1416 faceBaseImage.getHeight() != baseHeight ||
1417 faceBaseImage.getInternalFormat() != baseFormat )
1418 {
1419 return false;
1420 }
1421 }
1422
1423 return true;
1424}
1425
Brandon Jones6053a522014-07-25 16:22:09 -07001426void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1427{
1428 UNREACHABLE();
1429}
1430
1431void TextureD3D_Cube::releaseTexImage()
1432{
1433 UNREACHABLE();
1434}
1435
1436
Jamie Madill4aa79e12014-09-29 10:46:14 -04001437void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001438{
1439 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1440 int levelCount = mipLevels();
1441 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1442 {
1443 for (int level = 1; level < levelCount; level++)
1444 {
1445 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001446 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(),
1447 gl::Extents(faceLevelSize, faceLevelSize, 1));
Brandon Jones0511e802014-07-14 16:27:26 -07001448 }
1449 }
Brandon Jones0511e802014-07-14 16:27:26 -07001450}
1451
Jamie Madillac7579c2014-09-17 16:59:33 -04001452unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001453{
Geoff Lang8cb85c42015-01-07 13:23:26 -05001454 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001455}
1456
Geoff Lang64f23f62014-09-10 14:40:12 -04001457gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001458{
Geoff Lang691e58c2014-12-19 17:03:25 -05001459 ASSERT(gl::IsCubeMapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001460
1461 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001462 gl::Error error = ensureRenderTarget();
1463 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001464 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001465 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001466 }
1467
Geoff Langef7b0162014-09-04 13:29:23 -04001468 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1469 if (error.isError())
1470 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001471 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001472 }
1473
Geoff Lang64f23f62014-09-10 14:40:12 -04001474 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001475}
1476
Geoff Langef7b0162014-09-04 13:29:23 -04001477gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001478{
1479 // Only initialize the first time this texture is used as a render target or shader resource
1480 if (mTexStorage)
1481 {
Geoff Langef7b0162014-09-04 13:29:23 -04001482 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001483 }
1484
1485 // do not attempt to create storage for nonexistant data
1486 if (!isFaceLevelComplete(0, 0))
1487 {
Geoff Langef7b0162014-09-04 13:29:23 -04001488 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001489 }
1490
1491 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1492
Geoff Langef7b0162014-09-04 13:29:23 -04001493 TextureStorage *storage = NULL;
1494 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1495 if (error.isError())
1496 {
1497 return error;
1498 }
1499
1500 error = setCompleteTexStorage(storage);
1501 if (error.isError())
1502 {
1503 SafeDelete(storage);
1504 return error;
1505 }
1506
Brandon Jones0511e802014-07-14 16:27:26 -07001507 ASSERT(mTexStorage);
1508
1509 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001510 error = updateStorage();
1511 if (error.isError())
1512 {
1513 return error;
1514 }
1515
1516 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001517}
1518
Geoff Langef7b0162014-09-04 13:29:23 -04001519gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001520{
1521 GLsizei size = getBaseLevelWidth();
1522
1523 ASSERT(size > 0);
1524
1525 // use existing storage level count, when previously specified by TexStorage*D
1526 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1527
Geoff Langef7b0162014-09-04 13:29:23 -04001528 // TODO (geofflang): detect if storage creation succeeded
1529 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1530
1531 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001532}
1533
Geoff Langef7b0162014-09-04 13:29:23 -04001534gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001535{
Geoff Langef7b0162014-09-04 13:29:23 -04001536 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001537 {
1538 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1539 {
Geoff Langef7b0162014-09-04 13:29:23 -04001540 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001541 {
Geoff Langef7b0162014-09-04 13:29:23 -04001542 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1543 if (error.isError())
1544 {
1545 return error;
1546 }
Brandon Jones0511e802014-07-14 16:27:26 -07001547 }
1548 }
1549 }
1550
Geoff Langef7b0162014-09-04 13:29:23 -04001551 SafeDelete(mTexStorage);
1552 mTexStorage = newCompleteTexStorage;
1553
Brandon Jones0511e802014-07-14 16:27:26 -07001554 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001555 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001556}
1557
Geoff Langef7b0162014-09-04 13:29:23 -04001558gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001559{
1560 ASSERT(mTexStorage != NULL);
1561 GLint storageLevels = mTexStorage->getLevelCount();
1562 for (int face = 0; face < 6; face++)
1563 {
1564 for (int level = 0; level < storageLevels; level++)
1565 {
1566 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1567 {
Geoff Langef7b0162014-09-04 13:29:23 -04001568 gl::Error error = updateStorageFaceLevel(face, level);
1569 if (error.isError())
1570 {
1571 return error;
1572 }
Brandon Jones0511e802014-07-14 16:27:26 -07001573 }
1574 }
1575 }
Geoff Langef7b0162014-09-04 13:29:23 -04001576
1577 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001578}
1579
Brandon Jones0511e802014-07-14 16:27:26 -07001580bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1581{
1582 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1583}
1584
Brandon Jones0511e802014-07-14 16:27:26 -07001585bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1586{
1587 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1588
1589 if (isImmutable())
1590 {
1591 return true;
1592 }
1593
1594 int baseSize = getBaseLevelWidth();
1595
1596 if (baseSize <= 0)
1597 {
1598 return false;
1599 }
1600
1601 // "isCubeComplete" checks for base level completeness and we must call that
1602 // to determine if any face at level 0 is complete. We omit that check here
1603 // to avoid re-checking cube-completeness for every face at level 0.
1604 if (level == 0)
1605 {
1606 return true;
1607 }
1608
1609 // Check that non-zero levels are consistent with the base level.
1610 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1611
1612 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1613 {
1614 return false;
1615 }
1616
1617 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1618 {
1619 return false;
1620 }
1621
1622 return true;
1623}
1624
Jamie Madille76bdda2014-10-20 17:13:52 -04001625bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1626{
1627 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1628}
1629
Geoff Langef7b0162014-09-04 13:29:23 -04001630gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001631{
1632 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1633 ImageD3D *image = mImageArray[faceIndex][level];
1634
1635 if (image->isDirty())
1636 {
Geoff Lang691e58c2014-12-19 17:03:25 -05001637 GLenum faceTarget = gl::LayerIndexToCubeMapTextureTarget(faceIndex);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001638 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1639 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001640 gl::Error error = commitRegion(index, region);
1641 if (error.isError())
1642 {
1643 return error;
1644 }
Brandon Jones0511e802014-07-14 16:27:26 -07001645 }
Geoff Langef7b0162014-09-04 13:29:23 -04001646
1647 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001648}
1649
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001650void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones0511e802014-07-14 16:27:26 -07001651{
1652 // If there currently is a corresponding storage texture image, it has these parameters
1653 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1654 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1655 const GLenum storageFormat = getBaseLevelInternalFormat();
1656
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001657 mImageArray[faceIndex][level]->redefine(GL_TEXTURE_CUBE_MAP, internalformat, size, false);
Brandon Jones0511e802014-07-14 16:27:26 -07001658
1659 if (mTexStorage)
1660 {
1661 const int storageLevels = mTexStorage->getLevelCount();
1662
1663 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001664 size.width != storageWidth ||
1665 size.height != storageHeight ||
Brandon Jones0511e802014-07-14 16:27:26 -07001666 internalformat != storageFormat) // Discard mismatched storage
1667 {
1668 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1669 {
1670 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1671 {
1672 mImageArray[faceIndex][level]->markDirty();
1673 }
1674 }
1675
1676 SafeDelete(mTexStorage);
1677
1678 mDirtyImages = true;
1679 }
1680 }
1681}
1682
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001683gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1684{
1685 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1686}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001687
Jamie Madillcb83dc12014-09-29 10:46:12 -04001688gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1689{
1690 // The "layer" of the image index corresponds to the cube face
Geoff Lang691e58c2014-12-19 17:03:25 -05001691 return gl::ImageIndex::MakeCube(gl::LayerIndexToCubeMapTextureTarget(layer), mip);
Jamie Madillcb83dc12014-09-29 10:46:12 -04001692}
1693
Jamie Madill710e5772014-10-20 17:13:53 -04001694bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1695{
Geoff Lang691e58c2014-12-19 17:03:25 -05001696 return (mTexStorage && gl::IsCubeMapTextureTarget(index.type) &&
Jamie Madill710e5772014-10-20 17:13:53 -04001697 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1698}
1699
Jamie Madill93e13fb2014-11-06 15:27:25 -05001700TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001701 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001702{
1703 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1704 {
1705 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1706 }
1707}
1708
1709TextureD3D_3D::~TextureD3D_3D()
1710{
Austin Kinross69822602014-08-12 15:51:37 -07001711 // Delete the Images before the TextureStorage.
1712 // Images might be relying on the TextureStorage for some of their data.
1713 // 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 -07001714 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1715 {
1716 delete mImageArray[i];
1717 }
Austin Kinross69822602014-08-12 15:51:37 -07001718
1719 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001720}
1721
Brandon Jonescef06ff2014-08-05 13:27:48 -07001722Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001723{
1724 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001725 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001726 return mImageArray[level];
1727}
1728
Jamie Madillfeda4d22014-09-17 13:03:29 -04001729Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1730{
1731 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001732 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001733 ASSERT(index.type == GL_TEXTURE_3D);
1734 return mImageArray[index.mipIndex];
1735}
1736
Brandon Jonescef06ff2014-08-05 13:27:48 -07001737GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001738{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001739 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1740 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741}
1742
Brandon Jones78b1acd2014-07-15 15:33:07 -07001743GLsizei TextureD3D_3D::getWidth(GLint level) const
1744{
1745 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1746 return mImageArray[level]->getWidth();
1747 else
1748 return 0;
1749}
1750
1751GLsizei TextureD3D_3D::getHeight(GLint level) const
1752{
1753 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1754 return mImageArray[level]->getHeight();
1755 else
1756 return 0;
1757}
1758
1759GLsizei TextureD3D_3D::getDepth(GLint level) const
1760{
1761 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1762 return mImageArray[level]->getDepth();
1763 else
1764 return 0;
1765}
1766
1767GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1768{
1769 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1770 return mImageArray[level]->getInternalFormat();
1771 else
1772 return GL_NONE;
1773}
1774
1775bool TextureD3D_3D::isDepth(GLint level) const
1776{
Geoff Lang5d601382014-07-22 15:14:06 -04001777 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001778}
1779
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001780gl::Error TextureD3D_3D::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
1781 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001782{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001783 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001784 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1785
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001786 redefineImage(level, sizedInternalFormat, size);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001787
1788 bool fastUnpacked = false;
1789
Jamie Madillba6bc952014-10-06 10:56:22 -04001790 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1791
Brandon Jones78b1acd2014-07-15 15:33:07 -07001792 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
Jamie Madill3c9db122015-01-15 16:36:55 -05001793 if (isFastUnpackable(unpack, sizedInternalFormat) && !size.empty())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001794 {
1795 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001796 RenderTarget *destRenderTarget = NULL;
1797 gl::Error error = getRenderTarget(index, &destRenderTarget);
1798 if (error.isError())
1799 {
1800 return error;
1801 }
1802
Brandon Jones78b1acd2014-07-15 15:33:07 -07001803 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1804
Geoff Lang64f23f62014-09-10 14:40:12 -04001805 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1806 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001807 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001808 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001810
1811 // Ensure we don't overwrite our newly initialized data
1812 mImageArray[level]->markClean();
1813
1814 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001815 }
1816
1817 if (!fastUnpacked)
1818 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001819 gl::Error error = TextureD3D::setImage(index, type, unpack, pixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001820 if (error.isError())
1821 {
1822 return error;
1823 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001824 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001825
1826 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001827}
1828
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001829gl::Error TextureD3D_3D::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
1830 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001831{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001832 ASSERT(target == GL_TEXTURE_3D);
1833
Brandon Jones78b1acd2014-07-15 15:33:07 -07001834 bool fastUnpacked = false;
1835
Jamie Madillac7579c2014-09-17 16:59:33 -04001836 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1837
Brandon Jones78b1acd2014-07-15 15:33:07 -07001838 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1839 if (isFastUnpackable(unpack, getInternalFormat(level)))
1840 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001841 RenderTarget *destRenderTarget = NULL;
1842 gl::Error error = getRenderTarget(index, &destRenderTarget);
1843 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001844 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001845 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001846 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001847
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001848 error = fastUnpackPixels(unpack, pixels, area, getInternalFormat(level), type, destRenderTarget);
Geoff Lang64f23f62014-09-10 14:40:12 -04001849 if (error.isError())
1850 {
1851 return error;
1852 }
1853
1854 // Ensure we don't overwrite our newly initialized data
1855 mImageArray[level]->markClean();
1856
1857 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001858 }
1859
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001860 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001861 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001862 return TextureD3D::subImage(index, area, format, type, unpack, pixels);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001863 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001864
1865 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001866}
1867
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001868gl::Error TextureD3D_3D::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
1869 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001870{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001871 ASSERT(target == GL_TEXTURE_3D);
1872
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001873 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1874 redefineImage(level, internalFormat, size);
1875
1876 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1877 return TextureD3D::setCompressedImage(index, unpack, pixels);
1878}
1879
1880gl::Error TextureD3D_3D::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
1881 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
1882{
1883 ASSERT(target == GL_TEXTURE_3D);
1884
1885 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1886 gl::Error error = TextureD3D::subImageCompressed(index, area, format, unpack, pixels);
Geoff Langb5348332014-09-02 13:16:34 -04001887 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001888 {
Geoff Langb5348332014-09-02 13:16:34 -04001889 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001890 }
Geoff Langb5348332014-09-02 13:16:34 -04001891
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001892 return commitRegion(index, area);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001893}
1894
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001895gl::Error TextureD3D_3D::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
1896 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001897{
1898 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001899 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001900}
1901
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001902gl::Error TextureD3D_3D::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
1903 const gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001904{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001905 ASSERT(target == GL_TEXTURE_3D);
1906
Jamie Madille76bdda2014-10-20 17:13:52 -04001907 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001908
Jamie Madille76bdda2014-10-20 17:13:52 -04001909 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001910 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001911 gl::Error error = mImageArray[level]->copy(destOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04001912 if (error.isError())
1913 {
1914 return error;
1915 }
1916
Brandon Jones78b1acd2014-07-15 15:33:07 -07001917 mDirtyImages = true;
1918 }
1919 else
1920 {
Geoff Langef7b0162014-09-04 13:29:23 -04001921 gl::Error error = ensureRenderTarget();
1922 if (error.isError())
1923 {
1924 return error;
1925 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001926
1927 if (isValidLevel(level))
1928 {
Geoff Langef7b0162014-09-04 13:29:23 -04001929 error = updateStorageLevel(level);
1930 if (error.isError())
1931 {
1932 return error;
1933 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001934
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001935 error = mRenderer->copyImage3D(source, sourceArea,
Geoff Langef7b0162014-09-04 13:29:23 -04001936 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001937 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04001938 if (error.isError())
1939 {
1940 return error;
1941 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001942 }
1943 }
Geoff Langef7b0162014-09-04 13:29:23 -04001944
1945 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001946}
1947
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001948gl::Error TextureD3D_3D::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001950 ASSERT(target == GL_TEXTURE_3D);
1951
Geoff Lang8fed1f72015-01-09 11:09:33 -05001952 for (size_t level = 0; level < levels; level++)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001953 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001954 gl::Extents levelSize(std::max(1, size.width >> level),
1955 std::max(1, size.height >> level),
1956 std::max(1, size.depth >> level));
1957 mImageArray[level]->redefine(GL_TEXTURE_3D, internalFormat, levelSize, true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001958 }
1959
1960 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1961 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001962 mImageArray[level]->redefine(GL_TEXTURE_3D, GL_NONE, gl::Extents(0, 0, 0), true);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001963 }
1964
Geoff Lang1f8532b2014-09-05 09:46:13 -04001965 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001966 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001967 TextureStorage *storage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001968
1969 gl::Error error = setCompleteTexStorage(storage);
1970 if (error.isError())
1971 {
1972 SafeDelete(storage);
1973 return error;
1974 }
1975
1976 mImmutable = true;
1977
1978 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001979}
1980
Brandon Jones6053a522014-07-25 16:22:09 -07001981void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001982{
Brandon Jones6053a522014-07-25 16:22:09 -07001983 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001984}
1985
Brandon Jones6053a522014-07-25 16:22:09 -07001986void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001987{
Brandon Jones6053a522014-07-25 16:22:09 -07001988 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001989}
1990
Brandon Jones6053a522014-07-25 16:22:09 -07001991
Jamie Madill4aa79e12014-09-29 10:46:14 -04001992void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001993{
1994 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1995 int levelCount = mipLevels();
1996 for (int level = 1; level < levelCount; level++)
1997 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05001998 gl::Extents levelSize(std::max(getBaseLevelWidth() >> level, 1),
1999 std::max(getBaseLevelHeight() >> level, 1),
2000 std::max(getBaseLevelDepth() >> level, 1));
2001 redefineImage(level, getBaseLevelInternalFormat(), levelSize);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002003}
2004
Jamie Madillac7579c2014-09-17 16:59:33 -04002005unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002006{
Geoff Langef7b0162014-09-04 13:29:23 -04002007 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002008}
2009
Geoff Lang64f23f62014-09-10 14:40:12 -04002010gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002011{
2012 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002013 gl::Error error = ensureRenderTarget();
2014 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002015 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002016 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07002017 }
2018
Jamie Madillac7579c2014-09-17 16:59:33 -04002019 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002020 {
Geoff Langef7b0162014-09-04 13:29:23 -04002021 error = updateStorage();
2022 if (error.isError())
2023 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002024 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002025 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002026 }
2027 else
2028 {
Geoff Langef7b0162014-09-04 13:29:23 -04002029 error = updateStorageLevel(index.mipIndex);
2030 if (error.isError())
2031 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002032 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002033 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002034 }
2035
Geoff Lang64f23f62014-09-10 14:40:12 -04002036 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002037}
2038
Geoff Langef7b0162014-09-04 13:29:23 -04002039gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002040{
2041 // Only initialize the first time this texture is used as a render target or shader resource
2042 if (mTexStorage)
2043 {
Geoff Langef7b0162014-09-04 13:29:23 -04002044 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002045 }
2046
2047 // do not attempt to create storage for nonexistant data
2048 if (!isLevelComplete(0))
2049 {
Geoff Langef7b0162014-09-04 13:29:23 -04002050 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002051 }
2052
2053 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2054
Jamie Madill30d6c252014-11-13 10:03:33 -05002055 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002056 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2057 if (error.isError())
2058 {
2059 return error;
2060 }
2061
2062 error = setCompleteTexStorage(storage);
2063 if (error.isError())
2064 {
2065 SafeDelete(storage);
2066 return error;
2067 }
2068
Brandon Jones78b1acd2014-07-15 15:33:07 -07002069 ASSERT(mTexStorage);
2070
2071 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002072 error = updateStorage();
2073 if (error.isError())
2074 {
2075 return error;
2076 }
2077
2078 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002079}
2080
Geoff Langef7b0162014-09-04 13:29:23 -04002081gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002082{
2083 GLsizei width = getBaseLevelWidth();
2084 GLsizei height = getBaseLevelHeight();
2085 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002086 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002087
2088 ASSERT(width > 0 && height > 0 && depth > 0);
2089
2090 // use existing storage level count, when previously specified by TexStorage*D
2091 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2092
Geoff Langef7b0162014-09-04 13:29:23 -04002093 // TODO: Verify creation of the storage succeeded
2094 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2095
2096 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002097}
2098
Geoff Langef7b0162014-09-04 13:29:23 -04002099gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002100{
2101 SafeDelete(mTexStorage);
2102 mTexStorage = newCompleteTexStorage;
2103 mDirtyImages = true;
2104
2105 // We do not support managed 3D storage, as that is D3D9/ES2-only
2106 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002107
2108 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002109}
2110
Geoff Langef7b0162014-09-04 13:29:23 -04002111gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002112{
2113 ASSERT(mTexStorage != NULL);
2114 GLint storageLevels = mTexStorage->getLevelCount();
2115 for (int level = 0; level < storageLevels; level++)
2116 {
2117 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2118 {
Geoff Langef7b0162014-09-04 13:29:23 -04002119 gl::Error error = updateStorageLevel(level);
2120 if (error.isError())
2121 {
2122 return error;
2123 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002124 }
2125 }
Geoff Langef7b0162014-09-04 13:29:23 -04002126
2127 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002128}
2129
Brandon Jones78b1acd2014-07-15 15:33:07 -07002130bool TextureD3D_3D::isValidLevel(int level) const
2131{
2132 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2133}
2134
2135bool TextureD3D_3D::isLevelComplete(int level) const
2136{
2137 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2138
2139 if (isImmutable())
2140 {
2141 return true;
2142 }
2143
2144 GLsizei width = getBaseLevelWidth();
2145 GLsizei height = getBaseLevelHeight();
2146 GLsizei depth = getBaseLevelDepth();
2147
2148 if (width <= 0 || height <= 0 || depth <= 0)
2149 {
2150 return false;
2151 }
2152
2153 if (level == 0)
2154 {
2155 return true;
2156 }
2157
2158 ImageD3D *levelImage = mImageArray[level];
2159
2160 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2161 {
2162 return false;
2163 }
2164
2165 if (levelImage->getWidth() != std::max(1, width >> level))
2166 {
2167 return false;
2168 }
2169
2170 if (levelImage->getHeight() != std::max(1, height >> level))
2171 {
2172 return false;
2173 }
2174
2175 if (levelImage->getDepth() != std::max(1, depth >> level))
2176 {
2177 return false;
2178 }
2179
2180 return true;
2181}
2182
Jamie Madille76bdda2014-10-20 17:13:52 -04002183bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2184{
2185 return isLevelComplete(index.mipIndex);
2186}
2187
Geoff Langef7b0162014-09-04 13:29:23 -04002188gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002189{
2190 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2191 ASSERT(isLevelComplete(level));
2192
2193 if (mImageArray[level]->isDirty())
2194 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002195 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2196 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002197 gl::Error error = commitRegion(index, region);
2198 if (error.isError())
2199 {
2200 return error;
2201 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002202 }
Geoff Langef7b0162014-09-04 13:29:23 -04002203
2204 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002205}
2206
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002207void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002208{
2209 // If there currently is a corresponding storage texture image, it has these parameters
2210 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2211 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2212 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2213 const GLenum storageFormat = getBaseLevelInternalFormat();
2214
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002215 mImageArray[level]->redefine(GL_TEXTURE_3D, internalformat, size, false);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002216
2217 if (mTexStorage)
2218 {
2219 const int storageLevels = mTexStorage->getLevelCount();
2220
2221 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002222 size.width != storageWidth ||
2223 size.height != storageHeight ||
2224 size.depth != storageDepth ||
Brandon Jones78b1acd2014-07-15 15:33:07 -07002225 internalformat != storageFormat) // Discard mismatched storage
2226 {
2227 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2228 {
2229 mImageArray[i]->markDirty();
2230 }
2231
2232 SafeDelete(mTexStorage);
2233 mDirtyImages = true;
2234 }
2235 }
2236}
2237
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002238gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2239{
2240 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2241 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2242}
Brandon Jones142ec422014-07-16 10:31:30 -07002243
Jamie Madillcb83dc12014-09-29 10:46:12 -04002244gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2245{
2246 // The "layer" here does not apply to 3D images. We use one Image per mip.
2247 return gl::ImageIndex::Make3D(mip);
2248}
2249
Jamie Madill710e5772014-10-20 17:13:53 -04002250bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2251{
2252 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2253 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2254}
2255
Jamie Madill93e13fb2014-11-06 15:27:25 -05002256TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002257 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002258{
2259 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2260 {
2261 mLayerCounts[level] = 0;
2262 mImageArray[level] = NULL;
2263 }
2264}
2265
2266TextureD3D_2DArray::~TextureD3D_2DArray()
2267{
Austin Kinross69822602014-08-12 15:51:37 -07002268 // Delete the Images before the TextureStorage.
2269 // Images might be relying on the TextureStorage for some of their data.
2270 // 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 -07002271 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002272 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002273}
2274
Brandon Jones142ec422014-07-16 10:31:30 -07002275Image *TextureD3D_2DArray::getImage(int level, int layer) const
2276{
2277 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002278 ASSERT((layer == 0 && mLayerCounts[level] == 0) ||
2279 layer < mLayerCounts[level]);
2280 return (mImageArray[level] ? mImageArray[level][layer] : NULL);
Brandon Jones142ec422014-07-16 10:31:30 -07002281}
2282
Jamie Madillfeda4d22014-09-17 13:03:29 -04002283Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2284{
2285 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madille5685e02014-11-12 15:37:41 -05002286 ASSERT((index.layerIndex == 0 && mLayerCounts[index.mipIndex] == 0) ||
2287 index.layerIndex < mLayerCounts[index.mipIndex]);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002288 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
Jamie Madille5685e02014-11-12 15:37:41 -05002289 return (mImageArray[index.mipIndex] ? mImageArray[index.mipIndex][index.layerIndex] : NULL);
Jamie Madillfeda4d22014-09-17 13:03:29 -04002290}
2291
Brandon Jones142ec422014-07-16 10:31:30 -07002292GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2293{
2294 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2295 return mLayerCounts[level];
2296}
2297
Brandon Jones142ec422014-07-16 10:31:30 -07002298GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2299{
2300 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2301}
2302
2303GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2304{
2305 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2306}
2307
Brandon Jones142ec422014-07-16 10:31:30 -07002308GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2309{
2310 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2311}
2312
2313bool TextureD3D_2DArray::isDepth(GLint level) const
2314{
Geoff Lang5d601382014-07-22 15:14:06 -04002315 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002316}
2317
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002318gl::Error TextureD3D_2DArray::setImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size, GLenum format, GLenum type,
2319 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002320{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002321 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2322
Geoff Lang5d601382014-07-22 15:14:06 -04002323 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2324
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002325 redefineImage(level, sizedInternalFormat, size);
Brandon Jones142ec422014-07-16 10:31:30 -07002326
Geoff Lang5d601382014-07-22 15:14:06 -04002327 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002328 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, size.width, size.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002329
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002330 for (int i = 0; i < size.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002331 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002332 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002333 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002334 gl::Error error = TextureD3D::setImage(index, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002335 if (error.isError())
2336 {
2337 return error;
2338 }
Brandon Jones142ec422014-07-16 10:31:30 -07002339 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002340
2341 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002342}
2343
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002344gl::Error TextureD3D_2DArray::setSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type,
2345 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002346{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002347 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2348
Geoff Lang5d601382014-07-22 15:14:06 -04002349 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002350 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002351
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002352 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002353 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002354 int layer = area.z + i;
2355 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2356
2357 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002358
Jamie Madillfeda4d22014-09-17 13:03:29 -04002359 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002360 gl::Error error = TextureD3D::subImage(index, layerArea, format, type, unpack, layerPixels);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002361 if (error.isError())
2362 {
2363 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002364 }
2365 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002366
2367 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002368}
2369
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002370gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, size_t level, GLenum internalFormat, const gl::Extents &size,
2371 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
2372{
2373 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2374
2375 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2376 redefineImage(level, internalFormat, size);
2377
2378 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(internalFormat);
2379 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, size.width, size.height, 1);
2380
2381 for (int i = 0; i < size.depth; i++)
2382 {
2383 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
2384
2385 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2386 gl::Error error = TextureD3D::setCompressedImage(index, unpack, layerPixels);
2387 if (error.isError())
2388 {
2389 return error;
2390 }
2391 }
2392
2393 return gl::Error(GL_NO_ERROR);
2394}
2395
2396gl::Error TextureD3D_2DArray::setCompressedSubImage(GLenum target, size_t level, const gl::Box &area, GLenum format,
2397 const gl::PixelUnpackState &unpack, const uint8_t *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002398{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002399 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2400
Geoff Lang5d601382014-07-22 15:14:06 -04002401 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002402 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002403
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002404 for (int i = 0; i < area.depth; i++)
Brandon Jones142ec422014-07-16 10:31:30 -07002405 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002406 int layer = area.z + i;
2407 const uint8_t *layerPixels = pixels ? (pixels + (inputDepthPitch * i)) : NULL;
Brandon Jones142ec422014-07-16 10:31:30 -07002408
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002409 gl::Box layerArea(area.x, area.y, 0, area.width, area.height, 1);
2410
2411 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2412 gl::Error error = TextureD3D::subImageCompressed(index, layerArea, format, unpack, layerPixels);
Geoff Langb5348332014-09-02 13:16:34 -04002413 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002414 {
Geoff Langb5348332014-09-02 13:16:34 -04002415 return error;
2416 }
2417
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002418 error = commitRegion(index, layerArea);
Geoff Langb5348332014-09-02 13:16:34 -04002419 if (error.isError())
2420 {
2421 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002422 }
2423 }
Geoff Langb5348332014-09-02 13:16:34 -04002424
2425 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002426}
2427
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002428gl::Error TextureD3D_2DArray::copyImage(GLenum target, size_t level, const gl::Rectangle &sourceArea, GLenum internalFormat,
2429 const gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002430{
2431 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002432 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002433}
2434
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002435gl::Error TextureD3D_2DArray::copySubImage(GLenum target, size_t level, const gl::Offset &destOffset, const gl::Rectangle &sourceArea,
2436 const gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002437{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002438 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2439
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002440 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, destOffset.z);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002441
Jamie Madille76bdda2014-10-20 17:13:52 -04002442 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002443 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002444 gl::Offset destLayerOffset(destOffset.x, destOffset.y, 0);
2445 gl::Error error = mImageArray[level][destOffset.z]->copy(destLayerOffset, sourceArea, source);
Geoff Langef7b0162014-09-04 13:29:23 -04002446 if (error.isError())
2447 {
2448 return error;
2449 }
2450
Brandon Jones142ec422014-07-16 10:31:30 -07002451 mDirtyImages = true;
2452 }
2453 else
2454 {
Geoff Langef7b0162014-09-04 13:29:23 -04002455 gl::Error error = ensureRenderTarget();
2456 if (error.isError())
2457 {
2458 return error;
2459 }
Brandon Jones142ec422014-07-16 10:31:30 -07002460
2461 if (isValidLevel(level))
2462 {
Geoff Langef7b0162014-09-04 13:29:23 -04002463 error = updateStorageLevel(level);
2464 if (error.isError())
2465 {
2466 return error;
2467 }
Brandon Jones142ec422014-07-16 10:31:30 -07002468
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002469 error = mRenderer->copyImage2DArray(source, sourceArea, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2470 destOffset, mTexStorage, level);
Geoff Langef7b0162014-09-04 13:29:23 -04002471 if (error.isError())
2472 {
2473 return error;
2474 }
Brandon Jones142ec422014-07-16 10:31:30 -07002475 }
2476 }
Geoff Langef7b0162014-09-04 13:29:23 -04002477 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002478}
2479
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002480gl::Error TextureD3D_2DArray::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002481{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002482 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2483
Brandon Jones142ec422014-07-16 10:31:30 -07002484 deleteImages();
2485
Geoff Lang8fed1f72015-01-09 11:09:33 -05002486 for (size_t level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
Brandon Jones142ec422014-07-16 10:31:30 -07002487 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002488 gl::Extents levelLayerSize(std::max(1, size.width >> level),
2489 std::max(1, size.height >> level),
2490 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002491
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002492 mLayerCounts[level] = (level < levels ? size.depth : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002493
2494 if (mLayerCounts[level] > 0)
2495 {
2496 // Create new images for this level
2497 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2498
2499 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2500 {
2501 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002502 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalFormat, levelLayerSize, true);
Brandon Jones142ec422014-07-16 10:31:30 -07002503 }
2504 }
2505 }
2506
Geoff Lang1f8532b2014-09-05 09:46:13 -04002507 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002508 bool renderTarget = IsRenderTargetUsage(mUsage);
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002509 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, size.width, size.height, size.depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002510
2511 gl::Error error = setCompleteTexStorage(storage);
2512 if (error.isError())
2513 {
2514 SafeDelete(storage);
2515 return error;
2516 }
2517
2518 mImmutable = true;
2519
2520 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002521}
2522
Brandon Jones6053a522014-07-25 16:22:09 -07002523void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002524{
Brandon Jones6053a522014-07-25 16:22:09 -07002525 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002526}
2527
Brandon Jones6053a522014-07-25 16:22:09 -07002528void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002529{
Brandon Jones6053a522014-07-25 16:22:09 -07002530 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002531}
2532
Brandon Jones6053a522014-07-25 16:22:09 -07002533
Jamie Madill4aa79e12014-09-29 10:46:14 -04002534void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002535{
2536 int baseWidth = getBaseLevelWidth();
2537 int baseHeight = getBaseLevelHeight();
Jamie Madillf8fccb32014-11-12 15:05:26 -05002538 int baseDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002539 GLenum baseFormat = getBaseLevelInternalFormat();
2540
2541 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2542 int levelCount = mipLevels();
2543 for (int level = 1; level < levelCount; level++)
2544 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002545 gl::Extents levelLayerSize(std::max(baseWidth >> level, 1),
2546 std::max(baseHeight >> level, 1),
2547 baseDepth);
2548 redefineImage(level, baseFormat, levelLayerSize);
Brandon Jones142ec422014-07-16 10:31:30 -07002549 }
Brandon Jones142ec422014-07-16 10:31:30 -07002550}
2551
Jamie Madillac7579c2014-09-17 16:59:33 -04002552unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002553{
Geoff Langef7b0162014-09-04 13:29:23 -04002554 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002555}
2556
Geoff Lang64f23f62014-09-10 14:40:12 -04002557gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002558{
2559 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002560 gl::Error error = ensureRenderTarget();
2561 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002562 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002563 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002564 }
2565
Geoff Langef7b0162014-09-04 13:29:23 -04002566 error = updateStorageLevel(index.mipIndex);
2567 if (error.isError())
2568 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002569 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002570 }
2571
Geoff Lang64f23f62014-09-10 14:40:12 -04002572 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002573}
2574
Geoff Langef7b0162014-09-04 13:29:23 -04002575gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002576{
2577 // Only initialize the first time this texture is used as a render target or shader resource
2578 if (mTexStorage)
2579 {
Geoff Langef7b0162014-09-04 13:29:23 -04002580 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002581 }
2582
2583 // do not attempt to create storage for nonexistant data
2584 if (!isLevelComplete(0))
2585 {
Geoff Langef7b0162014-09-04 13:29:23 -04002586 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002587 }
2588
2589 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2590
Geoff Langef7b0162014-09-04 13:29:23 -04002591 TextureStorage *storage = NULL;
2592 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2593 if (error.isError())
2594 {
2595 return error;
2596 }
2597
2598 error = setCompleteTexStorage(storage);
2599 if (error.isError())
2600 {
2601 SafeDelete(storage);
2602 return error;
2603 }
2604
Brandon Jones142ec422014-07-16 10:31:30 -07002605 ASSERT(mTexStorage);
2606
2607 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002608 error = updateStorage();
2609 if (error.isError())
2610 {
2611 return error;
2612 }
2613
2614 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002615}
2616
Geoff Langef7b0162014-09-04 13:29:23 -04002617gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002618{
2619 GLsizei width = getBaseLevelWidth();
2620 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002621 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002622 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002623
2624 ASSERT(width > 0 && height > 0 && depth > 0);
2625
2626 // use existing storage level count, when previously specified by TexStorage*D
2627 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2628
Geoff Langef7b0162014-09-04 13:29:23 -04002629 // TODO(geofflang): Verify storage creation succeeds
2630 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2631
2632 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002633}
2634
Geoff Langef7b0162014-09-04 13:29:23 -04002635gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002636{
2637 SafeDelete(mTexStorage);
2638 mTexStorage = newCompleteTexStorage;
2639 mDirtyImages = true;
2640
2641 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2642 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002643
2644 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002645}
2646
Geoff Langef7b0162014-09-04 13:29:23 -04002647gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002648{
2649 ASSERT(mTexStorage != NULL);
2650 GLint storageLevels = mTexStorage->getLevelCount();
2651 for (int level = 0; level < storageLevels; level++)
2652 {
2653 if (isLevelComplete(level))
2654 {
Geoff Langef7b0162014-09-04 13:29:23 -04002655 gl::Error error = updateStorageLevel(level);
2656 if (error.isError())
2657 {
2658 return error;
2659 }
Brandon Jones142ec422014-07-16 10:31:30 -07002660 }
2661 }
Geoff Langef7b0162014-09-04 13:29:23 -04002662
2663 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002664}
2665
Brandon Jones142ec422014-07-16 10:31:30 -07002666bool TextureD3D_2DArray::isValidLevel(int level) const
2667{
2668 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2669}
2670
2671bool TextureD3D_2DArray::isLevelComplete(int level) const
2672{
2673 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2674
2675 if (isImmutable())
2676 {
2677 return true;
2678 }
2679
2680 GLsizei width = getBaseLevelWidth();
2681 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002682 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002683
2684 if (width <= 0 || height <= 0 || layers <= 0)
2685 {
2686 return false;
2687 }
2688
2689 if (level == 0)
2690 {
2691 return true;
2692 }
2693
2694 if (getInternalFormat(level) != getInternalFormat(0))
2695 {
2696 return false;
2697 }
2698
2699 if (getWidth(level) != std::max(1, width >> level))
2700 {
2701 return false;
2702 }
2703
2704 if (getHeight(level) != std::max(1, height >> level))
2705 {
2706 return false;
2707 }
2708
Jamie Madill3269bcb2014-09-30 16:33:52 -04002709 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002710 {
2711 return false;
2712 }
2713
2714 return true;
2715}
2716
Jamie Madille76bdda2014-10-20 17:13:52 -04002717bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2718{
2719 return isLevelComplete(index.mipIndex);
2720}
2721
Geoff Langef7b0162014-09-04 13:29:23 -04002722gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002723{
2724 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2725 ASSERT(isLevelComplete(level));
2726
2727 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2728 {
2729 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2730 if (mImageArray[level][layer]->isDirty())
2731 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002732 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2733 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002734 gl::Error error = commitRegion(index, region);
2735 if (error.isError())
2736 {
2737 return error;
2738 }
Brandon Jones142ec422014-07-16 10:31:30 -07002739 }
2740 }
Geoff Langef7b0162014-09-04 13:29:23 -04002741
2742 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002743}
2744
2745void TextureD3D_2DArray::deleteImages()
2746{
2747 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2748 {
2749 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2750 {
2751 delete mImageArray[level][layer];
2752 }
2753 delete[] mImageArray[level];
2754 mImageArray[level] = NULL;
2755 mLayerCounts[level] = 0;
2756 }
2757}
2758
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002759void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, const gl::Extents &size)
Brandon Jones142ec422014-07-16 10:31:30 -07002760{
2761 // If there currently is a corresponding storage texture image, it has these parameters
2762 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2763 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002764 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002765 const GLenum storageFormat = getBaseLevelInternalFormat();
2766
2767 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2768 {
2769 delete mImageArray[level][layer];
2770 }
2771 delete[] mImageArray[level];
2772 mImageArray[level] = NULL;
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002773 mLayerCounts[level] = size.depth;
Brandon Jones142ec422014-07-16 10:31:30 -07002774
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002775 if (size.depth > 0)
Brandon Jones142ec422014-07-16 10:31:30 -07002776 {
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002777 mImageArray[level] = new ImageD3D*[size.depth]();
Brandon Jones142ec422014-07-16 10:31:30 -07002778
2779 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2780 {
2781 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002782 mImageArray[level][layer]->redefine(GL_TEXTURE_2D_ARRAY, internalformat,
2783 gl::Extents(size.width, size.height, 1), false);
Brandon Jones142ec422014-07-16 10:31:30 -07002784 }
2785 }
2786
2787 if (mTexStorage)
2788 {
2789 const int storageLevels = mTexStorage->getLevelCount();
2790
2791 if ((level >= storageLevels && storageLevels != 0) ||
Geoff Lang0a4f1e22014-12-17 12:33:26 -05002792 size.width != storageWidth ||
2793 size.height != storageHeight ||
2794 size.depth != storageDepth ||
Brandon Jones142ec422014-07-16 10:31:30 -07002795 internalformat != storageFormat) // Discard mismatched storage
2796 {
2797 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2798 {
2799 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2800 {
2801 mImageArray[level][layer]->markDirty();
2802 }
2803 }
2804
2805 delete mTexStorage;
2806 mTexStorage = NULL;
2807 mDirtyImages = true;
2808 }
2809 }
2810}
2811
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002812gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2813{
2814 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2815}
2816
Jamie Madillcb83dc12014-09-29 10:46:12 -04002817gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2818{
2819 return gl::ImageIndex::Make2DArray(mip, layer);
2820}
2821
Jamie Madill710e5772014-10-20 17:13:53 -04002822bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2823{
2824 // Check for having a storage and the right type of index
2825 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2826 {
2827 return false;
2828 }
2829
2830 // Check the mip index
2831 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2832 {
2833 return false;
2834 }
2835
2836 // Check the layer index
2837 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2838}
2839
Brandon Jones78b1acd2014-07-15 15:33:07 -07002840}