blob: 1028b1bb831d56f4d26184bedc109dd3674a7348 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Geoff Lang0b7eef72014-06-12 14:10:47 -04009#include "libGLESv2/renderer/d3d/TextureD3D.h"
10#include "libGLESv2/renderer/d3d/TextureStorage.h"
11#include "libGLESv2/renderer/d3d/ImageD3D.h"
Jamie Madill9ae396b2014-10-21 17:46:30 -040012#include "libGLESv2/renderer/d3d/BufferD3D.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070013#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070014#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070015#include "libGLESv2/main.h"
16#include "libGLESv2/formatutils.h"
17#include "libGLESv2/renderer/BufferImpl.h"
18#include "libGLESv2/renderer/RenderTarget.h"
19#include "libGLESv2/renderer/Renderer.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040020
21#include "libEGL/Surface.h"
22
23#include "common/mathutil.h"
24#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070025
26namespace rx
27{
28
Jamie Madillc751d1e2014-10-21 17:46:29 -040029namespace
30{
31
32gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut)
33{
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 {
55 *pointerOut = static_cast<const uint8_t *>(pixels);
56 }
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
Brandon Jones78b1acd2014-07-15 15:33:07 -070068TextureD3D::TextureD3D(Renderer *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
Jamie Madillba6bc952014-10-06 10:56:22 -0400147gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
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 {
177 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
178 }
179
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400180 if (error.isError())
181 {
182 return error;
183 }
184
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700185 mDirtyImages = true;
186 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400187
188 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700189}
190
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400191gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
192 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700193{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400195 const uint8_t *pixelData = NULL;
196 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
197 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700198 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400199 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700200 }
201
202 if (pixelData != NULL)
203 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400204 Image *image = getImage(index);
205 ASSERT(image);
206
Jamie Madill9aca0592014-10-06 16:26:59 -0400207 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400208 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400209 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400210 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400211 }
212
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400213 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
214 type, pixelData);
215 if (error.isError())
216 {
217 return error;
218 }
219
Jamie Madille6b6da02014-10-02 11:03:14 -0400220 error = commitRegion(index, region);
221 if (error.isError())
222 {
223 return error;
224 }
225
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700226 mDirtyImages = true;
227 }
228
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400229 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700230}
231
Jamie Madillc751d1e2014-10-21 17:46:29 -0400232gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700233{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400234 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
235 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
236 const uint8_t *pixelData = NULL;
237 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
238 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700239 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400240 return error;
241 }
242
243 if (pixelData != NULL)
244 {
245 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400246 if (error.isError())
247 {
248 return error;
249 }
250
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700251 mDirtyImages = true;
252 }
Geoff Langb5348332014-09-02 13:16:34 -0400253
254 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700255}
256
Geoff Langb5348332014-09-02 13:16:34 -0400257gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400258 GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700259{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400260 const uint8_t *pixelData = NULL;
261 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
262 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700263 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400264 return error;
265 }
266
267 if (pixelData != NULL)
268 {
269 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400270 if (error.isError())
271 {
272 return error;
273 }
274
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700275 mDirtyImages = true;
276 }
277
Geoff Langb5348332014-09-02 13:16:34 -0400278 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700279}
280
281bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
282{
283 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
284}
285
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400286gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
287 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700288{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400289 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700290 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
291 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400292 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700293 }
294
295 // In order to perform the fast copy through the shader, we must have the right format, and be able
296 // to create a render target.
297 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
298
Jacek Cabana5521de2014-10-01 17:23:46 +0200299 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700300
Geoff Langae5122c2014-08-27 14:08:43 -0400301 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
302 if (error.isError())
303 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400304 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400305 }
306
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400307 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700308}
309
310GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
311{
312 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
313 {
314 // Maximum number of levels
315 return gl::log2(std::max(std::max(width, height), depth)) + 1;
316 }
317 else
318 {
319 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
320 return 1;
321 }
322}
323
324int TextureD3D::mipLevels() const
325{
326 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
327}
328
Jamie Madill98553e32014-09-30 16:33:50 -0400329TextureStorage *TextureD3D::getStorage()
330{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400331 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400332 return mTexStorage;
333}
334
Jamie Madill3269bcb2014-09-30 16:33:52 -0400335Image *TextureD3D::getBaseLevelImage() const
336{
337 return getImage(getImageIndex(0, 0));
338}
339
Jamie Madill4aa79e12014-09-29 10:46:14 -0400340void TextureD3D::generateMipmaps()
341{
Jamie Madill9aca0592014-10-06 16:26:59 -0400342 GLint mipCount = mipLevels();
343
344 if (mipCount == 1)
345 {
346 return; // no-op
347 }
348
349 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400350 initMipmapsImages();
351
352 // We know that all layers have the same dimension, for the texture to be complete
353 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400354
Jamie Madill9aca0592014-10-06 16:26:59 -0400355 // When making mipmaps with the setData workaround enabled, the texture storage has
356 // the image data already. For non-render-target storage, we have to pull it out into
357 // an image layer.
358 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
359 {
360 if (!mTexStorage->isRenderTarget())
361 {
362 // Copy from the storage mip 0 to Image mip 0
363 for (GLint layer = 0; layer < layerCount; ++layer)
364 {
365 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400366
Jamie Madill9aca0592014-10-06 16:26:59 -0400367 Image *image = getImage(srcIndex);
368 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
369 image->copy(0, 0, 0, area, srcIndex, mTexStorage);
370 }
371 }
372 else
373 {
374 updateStorage();
375 }
376 }
377
378 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400379
380 for (GLint layer = 0; layer < layerCount; ++layer)
381 {
382 for (GLint mip = 1; mip < mipCount; ++mip)
383 {
384 ASSERT(getLayerCount(mip) == layerCount);
385
386 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
387 gl::ImageIndex destIndex = getImageIndex(mip, layer);
388
389 if (renderableStorage)
390 {
391 // GPU-side mipmapping
Jamie Madill9aca0592014-10-06 16:26:59 -0400392 mTexStorage->generateMipmap(sourceIndex, destIndex);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400393 }
394 else
395 {
396 // CPU-side mipmapping
397 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
398 }
399 }
400 }
401}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700402
Jamie Madill135570a2014-09-30 16:33:51 -0400403bool TextureD3D::isBaseImageZeroSize() const
404{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400405 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400406
407 if (!baseImage || baseImage->getWidth() <= 0)
408 {
409 return true;
410 }
411
412 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
413 {
414 return true;
415 }
416
417 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
418 {
419 return true;
420 }
421
422 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
423 {
424 return true;
425 }
426
427 return false;
428}
429
Geoff Langef7b0162014-09-04 13:29:23 -0400430gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400431{
Geoff Langef7b0162014-09-04 13:29:23 -0400432 gl::Error error = initializeStorage(true);
433 if (error.isError())
434 {
435 return error;
436 }
Jamie Madill135570a2014-09-30 16:33:51 -0400437
438 if (!isBaseImageZeroSize())
439 {
440 ASSERT(mTexStorage);
441 if (!mTexStorage->isRenderTarget())
442 {
Geoff Langef7b0162014-09-04 13:29:23 -0400443 TextureStorage *newRenderTargetStorage = NULL;
444 error = createCompleteStorage(true, &newRenderTargetStorage);
445 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400446 {
Geoff Langef7b0162014-09-04 13:29:23 -0400447 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400448 }
449
Geoff Langef7b0162014-09-04 13:29:23 -0400450 error = mTexStorage->copyToStorage(newRenderTargetStorage);
451 if (error.isError())
452 {
453 SafeDelete(newRenderTargetStorage);
454 return error;
455 }
456
457 error = setCompleteTexStorage(newRenderTargetStorage);
458 if (error.isError())
459 {
460 SafeDelete(newRenderTargetStorage);
461 return error;
462 }
Jamie Madill135570a2014-09-30 16:33:51 -0400463 }
464 }
465
Geoff Langef7b0162014-09-04 13:29:23 -0400466 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400467}
468
Jamie Madille76bdda2014-10-20 17:13:52 -0400469bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
470{
471 rx::Image *image = getImage(index);
472 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
473 return (image->isRenderableFormat() && levelsComplete);
474}
475
Jamie Madill710e5772014-10-20 17:13:53 -0400476gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
477{
478 if (mTexStorage)
479 {
480 ASSERT(isValidIndex(index));
481 Image *image = getImage(index);
482 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
483 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
484 if (error.isError())
485 {
486 return error;
487 }
488
489 image->markClean();
490 }
491
492 return gl::Error(GL_NO_ERROR);
493}
494
Brandon Jones78b1acd2014-07-15 15:33:07 -0700495TextureD3D_2D::TextureD3D_2D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400496 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700497{
498 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
499 {
500 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
501 }
502}
503
504TextureD3D_2D::~TextureD3D_2D()
505{
Austin Kinross69822602014-08-12 15:51:37 -0700506 // Delete the Images before the TextureStorage.
507 // Images might be relying on the TextureStorage for some of their data.
508 // 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 -0700509 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
510 {
511 delete mImageArray[i];
512 }
Austin Kinross69822602014-08-12 15:51:37 -0700513
514 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700515}
516
Brandon Jonescef06ff2014-08-05 13:27:48 -0700517Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700518{
519 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700520 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700521 return mImageArray[level];
522}
523
Jamie Madillfeda4d22014-09-17 13:03:29 -0400524Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
525{
526 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400527 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400528 ASSERT(index.type == GL_TEXTURE_2D);
529 return mImageArray[index.mipIndex];
530}
531
Brandon Jonescef06ff2014-08-05 13:27:48 -0700532GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700533{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700534 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
535 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700536}
537
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700538GLsizei TextureD3D_2D::getWidth(GLint level) const
539{
540 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
541 return mImageArray[level]->getWidth();
542 else
543 return 0;
544}
545
546GLsizei TextureD3D_2D::getHeight(GLint level) const
547{
548 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
549 return mImageArray[level]->getHeight();
550 else
551 return 0;
552}
553
554GLenum TextureD3D_2D::getInternalFormat(GLint level) const
555{
556 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
557 return mImageArray[level]->getInternalFormat();
558 else
559 return GL_NONE;
560}
561
562GLenum TextureD3D_2D::getActualFormat(GLint level) const
563{
564 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
565 return mImageArray[level]->getActualFormat();
566 else
567 return GL_NONE;
568}
569
570bool TextureD3D_2D::isDepth(GLint level) const
571{
Geoff Lang5d601382014-07-22 15:14:06 -0400572 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700573}
574
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400575gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
576 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
577 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700578{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700579 ASSERT(target == GL_TEXTURE_2D && depth == 1);
580
Geoff Lang5d601382014-07-22 15:14:06 -0400581 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
582
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700583 bool fastUnpacked = false;
584
Brandon Jonescef06ff2014-08-05 13:27:48 -0700585 redefineImage(level, sizedInternalFormat, width, height);
586
Jamie Madillba6bc952014-10-06 10:56:22 -0400587 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
588
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700589 // Attempt a fast gpu copy of the pixel data to the surface
590 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
591 {
592 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400593 RenderTarget *destRenderTarget = NULL;
594 gl::Error error = getRenderTarget(index, &destRenderTarget);
595 if (error.isError())
596 {
597 return error;
598 }
599
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700600 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
601
Geoff Lang64f23f62014-09-10 14:40:12 -0400602 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
603 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700604 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400605 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700606 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400607
608 // Ensure we don't overwrite our newly initialized data
609 mImageArray[level]->markClean();
610
611 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700612 }
613
614 if (!fastUnpacked)
615 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400616 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400617 if (error.isError())
618 {
619 return error;
620 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700621 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400622
623 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700624}
625
Geoff Langb5348332014-09-02 13:16:34 -0400626gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
627 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400628 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700629{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700630 ASSERT(target == GL_TEXTURE_2D && depth == 1);
631
632 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
633 redefineImage(level, format, width, height);
634
Jamie Madillc751d1e2014-10-21 17:46:29 -0400635 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700636}
637
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400638gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
639 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
640 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700641{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700642 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
643
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700644 bool fastUnpacked = false;
645
Jamie Madillac7579c2014-09-17 16:59:33 -0400646 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400647 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700648 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
649 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400650 RenderTarget *renderTarget = NULL;
651 gl::Error error = getRenderTarget(index, &renderTarget);
652 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700653 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400654 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700655 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400656
657 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
658 if (error.isError())
659 {
660 return error;
661 }
662
663 // Ensure we don't overwrite our newly initialized data
664 mImageArray[level]->markClean();
665
666 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667 }
668
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400669 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700670 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400671 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
672 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700673 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400674
675 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700676}
677
Geoff Langb5348332014-09-02 13:16:34 -0400678gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
679 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400680 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700681{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700682 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
683
Jamie Madillc751d1e2014-10-21 17:46:29 -0400684 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -0400685 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 {
Geoff Langb5348332014-09-02 13:16:34 -0400687 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700688 }
Geoff Langb5348332014-09-02 13:16:34 -0400689
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400690 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
691 gl::Box region(xoffset, yoffset, 0, width, height, 1);
692 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700693}
694
Geoff Langef7b0162014-09-04 13:29:23 -0400695gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
696 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700697{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700698 ASSERT(target == GL_TEXTURE_2D);
699
700 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
701 redefineImage(level, sizedInternalFormat, width, height);
702
Jamie Madill82bf0c52014-10-03 11:50:53 -0400703 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400704 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400705
Jamie Madille76bdda2014-10-20 17:13:52 -0400706 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700707 {
Geoff Langef7b0162014-09-04 13:29:23 -0400708 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
709 if (error.isError())
710 {
711 return error;
712 }
713
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700714 mDirtyImages = true;
715 }
716 else
717 {
Geoff Langef7b0162014-09-04 13:29:23 -0400718 gl::Error error = ensureRenderTarget();
719 if (error.isError())
720 {
721 return error;
722 }
723
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700724 mImageArray[level]->markClean();
725
726 if (width != 0 && height != 0 && isValidLevel(level))
727 {
Geoff Langef7b0162014-09-04 13:29:23 -0400728 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
729 if (error.isError())
730 {
731 return error;
732 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733 }
734 }
Geoff Langef7b0162014-09-04 13:29:23 -0400735
736 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700737}
738
Geoff Langef7b0162014-09-04 13:29:23 -0400739gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
740 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700741{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700742 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
743
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700744 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
745 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700746
Jamie Madill82bf0c52014-10-03 11:50:53 -0400747 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400748 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400749
Jamie Madille76bdda2014-10-20 17:13:52 -0400750 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700751 {
Geoff Langef7b0162014-09-04 13:29:23 -0400752 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
753 if (error.isError())
754 {
755 return error;
756 }
757
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700758 mDirtyImages = true;
759 }
760 else
761 {
Geoff Langef7b0162014-09-04 13:29:23 -0400762 gl::Error error = ensureRenderTarget();
763 if (error.isError())
764 {
765 return error;
766 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700767
768 if (isValidLevel(level))
769 {
Geoff Langef7b0162014-09-04 13:29:23 -0400770 error = updateStorageLevel(level);
771 if (error.isError())
772 {
773 return error;
774 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700775
Geoff Langef7b0162014-09-04 13:29:23 -0400776 error = mRenderer->copyImage2D(source, sourceRect,
777 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
778 xoffset, yoffset, mTexStorage, level);
779 if (error.isError())
780 {
781 return error;
782 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700783 }
784 }
Geoff Langef7b0162014-09-04 13:29:23 -0400785
786 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700787}
788
Geoff Lang1f8532b2014-09-05 09:46:13 -0400789gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700790{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700791 ASSERT(target == GL_TEXTURE_2D && depth == 1);
792
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700793 for (int level = 0; level < levels; level++)
794 {
795 GLsizei levelWidth = std::max(1, width >> level);
796 GLsizei levelHeight = std::max(1, height >> level);
797 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
798 }
799
800 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
801 {
802 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
803 }
804
Geoff Lang1f8532b2014-09-05 09:46:13 -0400805 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400806 bool renderTarget = IsRenderTargetUsage(mUsage);
807 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400808
809 gl::Error error = setCompleteTexStorage(storage);
810 if (error.isError())
811 {
812 SafeDelete(storage);
813 return error;
814 }
815
816 mImmutable = true;
817
818 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700819}
820
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700821void TextureD3D_2D::bindTexImage(egl::Surface *surface)
822{
823 GLenum internalformat = surface->getFormat();
824
825 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
826
827 if (mTexStorage)
828 {
829 SafeDelete(mTexStorage);
830 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400831
832 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700833
834 mDirtyImages = true;
835}
836
837void TextureD3D_2D::releaseTexImage()
838{
839 if (mTexStorage)
840 {
841 SafeDelete(mTexStorage);
842 }
843
844 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
845 {
846 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
847 }
848}
849
Jamie Madill4aa79e12014-09-29 10:46:14 -0400850void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700851{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700852 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700853 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700854 for (int level = 1; level < levelCount; level++)
855 {
856 redefineImage(level, getBaseLevelInternalFormat(),
857 std::max(getBaseLevelWidth() >> level, 1),
858 std::max(getBaseLevelHeight() >> level, 1));
859 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700860}
861
Jamie Madillac7579c2014-09-17 16:59:33 -0400862unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700863{
Jamie Madillac7579c2014-09-17 16:59:33 -0400864 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400865 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700866}
867
Geoff Lang64f23f62014-09-10 14:40:12 -0400868gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700869{
Jamie Madillac7579c2014-09-17 16:59:33 -0400870 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700871
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700872 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400873 gl::Error error = ensureRenderTarget();
874 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700875 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400876 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700877 }
878
Geoff Langef7b0162014-09-04 13:29:23 -0400879 error = updateStorageLevel(index.mipIndex);
880 if (error.isError())
881 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400882 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400883 }
884
Geoff Lang64f23f62014-09-10 14:40:12 -0400885 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700886}
887
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700888bool TextureD3D_2D::isValidLevel(int level) const
889{
890 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
891}
892
893bool TextureD3D_2D::isLevelComplete(int level) const
894{
895 if (isImmutable())
896 {
897 return true;
898 }
899
Brandon Jones78b1acd2014-07-15 15:33:07 -0700900 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700901
902 GLsizei width = baseImage->getWidth();
903 GLsizei height = baseImage->getHeight();
904
905 if (width <= 0 || height <= 0)
906 {
907 return false;
908 }
909
910 // The base image level is complete if the width and height are positive
911 if (level == 0)
912 {
913 return true;
914 }
915
916 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700917 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700918
919 if (image->getInternalFormat() != baseImage->getInternalFormat())
920 {
921 return false;
922 }
923
924 if (image->getWidth() != std::max(1, width >> level))
925 {
926 return false;
927 }
928
929 if (image->getHeight() != std::max(1, height >> level))
930 {
931 return false;
932 }
933
934 return true;
935}
936
Jamie Madille76bdda2014-10-20 17:13:52 -0400937bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
938{
939 return isLevelComplete(index.mipIndex);
940}
941
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700942// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400943gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700944{
945 // Only initialize the first time this texture is used as a render target or shader resource
946 if (mTexStorage)
947 {
Geoff Langef7b0162014-09-04 13:29:23 -0400948 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700949 }
950
951 // do not attempt to create storage for nonexistant data
952 if (!isLevelComplete(0))
953 {
Geoff Langef7b0162014-09-04 13:29:23 -0400954 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700955 }
956
957 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
958
Geoff Langef7b0162014-09-04 13:29:23 -0400959 TextureStorage *storage = NULL;
960 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
961 if (error.isError())
962 {
963 return error;
964 }
965
966 error = setCompleteTexStorage(storage);
967 if (error.isError())
968 {
969 SafeDelete(storage);
970 return error;
971 }
972
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700973 ASSERT(mTexStorage);
974
975 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400976 error = updateStorage();
977 if (error.isError())
978 {
979 return error;
980 }
981
982 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700983}
984
Geoff Langef7b0162014-09-04 13:29:23 -0400985gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700986{
987 GLsizei width = getBaseLevelWidth();
988 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -0400989 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700990
991 ASSERT(width > 0 && height > 0);
992
993 // use existing storage level count, when previously specified by TexStorage*D
994 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
995
Geoff Langef7b0162014-09-04 13:29:23 -0400996 // TODO(geofflang): Determine if the texture creation succeeded
997 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
998
999 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001000}
1001
Geoff Langef7b0162014-09-04 13:29:23 -04001002gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001003{
Geoff Langef7b0162014-09-04 13:29:23 -04001004 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001005 {
Geoff Langef7b0162014-09-04 13:29:23 -04001006 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001007 {
Geoff Langef7b0162014-09-04 13:29:23 -04001008 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1009 if (error.isError())
1010 {
1011 return error;
1012 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001013 }
1014 }
1015
Geoff Langef7b0162014-09-04 13:29:23 -04001016 SafeDelete(mTexStorage);
1017 mTexStorage = newCompleteTexStorage;
1018
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001019 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001020
1021 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001022}
1023
Geoff Langef7b0162014-09-04 13:29:23 -04001024gl::Error TextureD3D_2D::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001025{
1026 ASSERT(mTexStorage != NULL);
1027 GLint storageLevels = mTexStorage->getLevelCount();
1028 for (int level = 0; level < storageLevels; level++)
1029 {
1030 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1031 {
Geoff Langef7b0162014-09-04 13:29:23 -04001032 gl::Error error = updateStorageLevel(level);
1033 if (error.isError())
1034 {
1035 return error;
1036 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001037 }
1038 }
Geoff Langef7b0162014-09-04 13:29:23 -04001039
1040 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001041}
1042
Geoff Langef7b0162014-09-04 13:29:23 -04001043gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001044{
1045 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1046 ASSERT(isLevelComplete(level));
1047
1048 if (mImageArray[level]->isDirty())
1049 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001050 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1051 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001052 gl::Error error = commitRegion(index, region);
1053 if (error.isError())
1054 {
1055 return error;
1056 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001057 }
Geoff Langef7b0162014-09-04 13:29:23 -04001058
1059 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001060}
1061
1062void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1063{
1064 // If there currently is a corresponding storage texture image, it has these parameters
1065 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1066 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1067 const GLenum storageFormat = getBaseLevelInternalFormat();
1068
1069 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1070
1071 if (mTexStorage)
1072 {
1073 const int storageLevels = mTexStorage->getLevelCount();
1074
1075 if ((level >= storageLevels && storageLevels != 0) ||
1076 width != storageWidth ||
1077 height != storageHeight ||
1078 internalformat != storageFormat) // Discard mismatched storage
1079 {
1080 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1081 {
1082 mImageArray[i]->markDirty();
1083 }
1084
1085 SafeDelete(mTexStorage);
1086 mDirtyImages = true;
1087 }
1088 }
1089}
1090
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001091gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1092{
1093 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1094}
Brandon Jones0511e802014-07-14 16:27:26 -07001095
Jamie Madillcb83dc12014-09-29 10:46:12 -04001096gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1097{
1098 // "layer" does not apply to 2D Textures.
1099 return gl::ImageIndex::Make2D(mip);
1100}
1101
Jamie Madill710e5772014-10-20 17:13:53 -04001102bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1103{
1104 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1105 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1106}
1107
Brandon Jones78b1acd2014-07-15 15:33:07 -07001108TextureD3D_Cube::TextureD3D_Cube(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001109 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001110{
1111 for (int i = 0; i < 6; i++)
1112 {
1113 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1114 {
1115 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1116 }
1117 }
1118}
1119
1120TextureD3D_Cube::~TextureD3D_Cube()
1121{
Austin Kinross69822602014-08-12 15:51:37 -07001122 // Delete the Images before the TextureStorage.
1123 // Images might be relying on the TextureStorage for some of their data.
1124 // 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 -07001125 for (int i = 0; i < 6; i++)
1126 {
1127 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1128 {
1129 SafeDelete(mImageArray[i][j]);
1130 }
1131 }
Austin Kinross69822602014-08-12 15:51:37 -07001132
1133 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001134}
1135
Brandon Jonescef06ff2014-08-05 13:27:48 -07001136Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001137{
1138 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001139 ASSERT(layer < 6);
1140 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001141}
1142
Jamie Madillfeda4d22014-09-17 13:03:29 -04001143Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1144{
1145 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1146 ASSERT(index.layerIndex < 6);
1147 return mImageArray[index.layerIndex][index.mipIndex];
1148}
1149
Brandon Jonescef06ff2014-08-05 13:27:48 -07001150GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001151{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001152 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1153 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001154}
1155
Brandon Jonescef06ff2014-08-05 13:27:48 -07001156GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001157{
1158 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001159 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001160 else
1161 return GL_NONE;
1162}
1163
Brandon Jonescef06ff2014-08-05 13:27:48 -07001164bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001165{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001166 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001167}
1168
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001169gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1170 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1171 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001172{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001173 ASSERT(depth == 1);
1174
Geoff Lang5d601382014-07-22 15:14:06 -04001175 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001176 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001177
Jamie Madillba6bc952014-10-06 10:56:22 -04001178 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001179
Jamie Madillba6bc952014-10-06 10:56:22 -04001180 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001181}
1182
Geoff Langb5348332014-09-02 13:16:34 -04001183gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1184 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001185 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001186{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001187 ASSERT(depth == 1);
1188
Brandon Jones0511e802014-07-14 16:27:26 -07001189 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001190 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1191
Brandon Jones0511e802014-07-14 16:27:26 -07001192 redefineImage(faceIndex, level, format, width, height);
1193
Jamie Madillc751d1e2014-10-21 17:46:29 -04001194 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001195}
1196
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001197gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1198 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1199 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001200{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001201 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001202 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001203 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001204}
1205
Geoff Langb5348332014-09-02 13:16:34 -04001206gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1207 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001208 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001209{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001210 ASSERT(depth == 1 && zoffset == 0);
1211
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001212 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001213
Jamie Madillc751d1e2014-10-21 17:46:29 -04001214 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[index.layerIndex][level]);
Geoff Langb5348332014-09-02 13:16:34 -04001215 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001216 {
Geoff Langb5348332014-09-02 13:16:34 -04001217 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001218 }
Geoff Langb5348332014-09-02 13:16:34 -04001219
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001220 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1221 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001222}
1223
Geoff Langef7b0162014-09-04 13:29:23 -04001224gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1225 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001226{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001227 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001228 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1229
Brandon Jones0511e802014-07-14 16:27:26 -07001230 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1231
Jamie Madill82bf0c52014-10-03 11:50:53 -04001232 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001233 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001234
Jamie Madille76bdda2014-10-20 17:13:52 -04001235 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001236 {
Geoff Langef7b0162014-09-04 13:29:23 -04001237 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1238 if (error.isError())
1239 {
1240 return error;
1241 }
1242
Brandon Jones0511e802014-07-14 16:27:26 -07001243 mDirtyImages = true;
1244 }
1245 else
1246 {
Geoff Langef7b0162014-09-04 13:29:23 -04001247 gl::Error error = ensureRenderTarget();
1248 if (error.isError())
1249 {
1250 return error;
1251 }
1252
Brandon Jones0511e802014-07-14 16:27:26 -07001253 mImageArray[faceIndex][level]->markClean();
1254
1255 ASSERT(width == height);
1256
1257 if (width > 0 && isValidFaceLevel(faceIndex, level))
1258 {
Geoff Langef7b0162014-09-04 13:29:23 -04001259 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1260 if (error.isError())
1261 {
1262 return error;
1263 }
Brandon Jones0511e802014-07-14 16:27:26 -07001264 }
1265 }
Geoff Langef7b0162014-09-04 13:29:23 -04001266
1267 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001268}
1269
Geoff Langef7b0162014-09-04 13:29:23 -04001270gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1271 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001272{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001273 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001274
Jamie Madill82bf0c52014-10-03 11:50:53 -04001275 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001276 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001277
Jamie Madille76bdda2014-10-20 17:13:52 -04001278 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001279 {
Geoff Langef7b0162014-09-04 13:29:23 -04001280 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1281 if (error.isError())
1282 {
1283 return error;
1284 }
1285
Brandon Jones0511e802014-07-14 16:27:26 -07001286 mDirtyImages = true;
1287 }
1288 else
1289 {
Geoff Langef7b0162014-09-04 13:29:23 -04001290 gl::Error error = ensureRenderTarget();
1291 if (error.isError())
1292 {
1293 return error;
1294 }
Brandon Jones0511e802014-07-14 16:27:26 -07001295
1296 if (isValidFaceLevel(faceIndex, level))
1297 {
Geoff Langef7b0162014-09-04 13:29:23 -04001298 error = updateStorageFaceLevel(faceIndex, level);
1299 if (error.isError())
1300 {
1301 return error;
1302 }
Brandon Jones0511e802014-07-14 16:27:26 -07001303
Geoff Langef7b0162014-09-04 13:29:23 -04001304 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1305 xoffset, yoffset, mTexStorage, target, level);
1306 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 Lang1f8532b2014-09-05 09:46:13 -04001316gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001317{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001318 ASSERT(width == height);
1319 ASSERT(depth == 1);
1320
Brandon Jones0511e802014-07-14 16:27:26 -07001321 for (int level = 0; level < levels; level++)
1322 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001323 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001324 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1325 {
1326 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1327 }
1328 }
1329
1330 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1331 {
1332 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1333 {
1334 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1335 }
1336 }
1337
Geoff Lang1f8532b2014-09-05 09:46:13 -04001338 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001339 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001340 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001341
1342 gl::Error error = setCompleteTexStorage(storage);
1343 if (error.isError())
1344 {
1345 SafeDelete(storage);
1346 return error;
1347 }
1348
1349 mImmutable = true;
1350
1351 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001352}
1353
Brandon Jones0511e802014-07-14 16:27:26 -07001354// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1355bool TextureD3D_Cube::isCubeComplete() const
1356{
1357 int baseWidth = getBaseLevelWidth();
1358 int baseHeight = getBaseLevelHeight();
1359 GLenum baseFormat = getBaseLevelInternalFormat();
1360
1361 if (baseWidth <= 0 || baseWidth != baseHeight)
1362 {
1363 return false;
1364 }
1365
1366 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1367 {
1368 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1369
1370 if (faceBaseImage.getWidth() != baseWidth ||
1371 faceBaseImage.getHeight() != baseHeight ||
1372 faceBaseImage.getInternalFormat() != baseFormat )
1373 {
1374 return false;
1375 }
1376 }
1377
1378 return true;
1379}
1380
Brandon Jones6053a522014-07-25 16:22:09 -07001381void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1382{
1383 UNREACHABLE();
1384}
1385
1386void TextureD3D_Cube::releaseTexImage()
1387{
1388 UNREACHABLE();
1389}
1390
1391
Jamie Madill4aa79e12014-09-29 10:46:14 -04001392void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001393{
1394 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1395 int levelCount = mipLevels();
1396 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1397 {
1398 for (int level = 1; level < levelCount; level++)
1399 {
1400 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1401 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1402 }
1403 }
Brandon Jones0511e802014-07-14 16:27:26 -07001404}
1405
Jamie Madillac7579c2014-09-17 16:59:33 -04001406unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001407{
Geoff Langef7b0162014-09-04 13:29:23 -04001408 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001409}
1410
Geoff Lang64f23f62014-09-10 14:40:12 -04001411gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001412{
Jamie Madillac7579c2014-09-17 16:59:33 -04001413 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001414
1415 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001416 gl::Error error = ensureRenderTarget();
1417 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001418 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001419 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001420 }
1421
Geoff Langef7b0162014-09-04 13:29:23 -04001422 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1423 if (error.isError())
1424 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001425 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001426 }
1427
Geoff Lang64f23f62014-09-10 14:40:12 -04001428 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001429}
1430
Geoff Langef7b0162014-09-04 13:29:23 -04001431gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001432{
1433 // Only initialize the first time this texture is used as a render target or shader resource
1434 if (mTexStorage)
1435 {
Geoff Langef7b0162014-09-04 13:29:23 -04001436 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001437 }
1438
1439 // do not attempt to create storage for nonexistant data
1440 if (!isFaceLevelComplete(0, 0))
1441 {
Geoff Langef7b0162014-09-04 13:29:23 -04001442 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001443 }
1444
1445 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1446
Geoff Langef7b0162014-09-04 13:29:23 -04001447 TextureStorage *storage = NULL;
1448 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1449 if (error.isError())
1450 {
1451 return error;
1452 }
1453
1454 error = setCompleteTexStorage(storage);
1455 if (error.isError())
1456 {
1457 SafeDelete(storage);
1458 return error;
1459 }
1460
Brandon Jones0511e802014-07-14 16:27:26 -07001461 ASSERT(mTexStorage);
1462
1463 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001464 error = updateStorage();
1465 if (error.isError())
1466 {
1467 return error;
1468 }
1469
1470 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001471}
1472
Geoff Langef7b0162014-09-04 13:29:23 -04001473gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001474{
1475 GLsizei size = getBaseLevelWidth();
1476
1477 ASSERT(size > 0);
1478
1479 // use existing storage level count, when previously specified by TexStorage*D
1480 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1481
Geoff Langef7b0162014-09-04 13:29:23 -04001482 // TODO (geofflang): detect if storage creation succeeded
1483 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1484
1485 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001486}
1487
Geoff Langef7b0162014-09-04 13:29:23 -04001488gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001489{
Geoff Langef7b0162014-09-04 13:29:23 -04001490 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001491 {
1492 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1493 {
Geoff Langef7b0162014-09-04 13:29:23 -04001494 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001495 {
Geoff Langef7b0162014-09-04 13:29:23 -04001496 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1497 if (error.isError())
1498 {
1499 return error;
1500 }
Brandon Jones0511e802014-07-14 16:27:26 -07001501 }
1502 }
1503 }
1504
Geoff Langef7b0162014-09-04 13:29:23 -04001505 SafeDelete(mTexStorage);
1506 mTexStorage = newCompleteTexStorage;
1507
Brandon Jones0511e802014-07-14 16:27:26 -07001508 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001509 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001510}
1511
Geoff Langef7b0162014-09-04 13:29:23 -04001512gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001513{
1514 ASSERT(mTexStorage != NULL);
1515 GLint storageLevels = mTexStorage->getLevelCount();
1516 for (int face = 0; face < 6; face++)
1517 {
1518 for (int level = 0; level < storageLevels; level++)
1519 {
1520 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1521 {
Geoff Langef7b0162014-09-04 13:29:23 -04001522 gl::Error error = updateStorageFaceLevel(face, level);
1523 if (error.isError())
1524 {
1525 return error;
1526 }
Brandon Jones0511e802014-07-14 16:27:26 -07001527 }
1528 }
1529 }
Geoff Langef7b0162014-09-04 13:29:23 -04001530
1531 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001532}
1533
Brandon Jones0511e802014-07-14 16:27:26 -07001534bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1535{
1536 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1537}
1538
Brandon Jones0511e802014-07-14 16:27:26 -07001539bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1540{
1541 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1542
1543 if (isImmutable())
1544 {
1545 return true;
1546 }
1547
1548 int baseSize = getBaseLevelWidth();
1549
1550 if (baseSize <= 0)
1551 {
1552 return false;
1553 }
1554
1555 // "isCubeComplete" checks for base level completeness and we must call that
1556 // to determine if any face at level 0 is complete. We omit that check here
1557 // to avoid re-checking cube-completeness for every face at level 0.
1558 if (level == 0)
1559 {
1560 return true;
1561 }
1562
1563 // Check that non-zero levels are consistent with the base level.
1564 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1565
1566 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1567 {
1568 return false;
1569 }
1570
1571 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1572 {
1573 return false;
1574 }
1575
1576 return true;
1577}
1578
Jamie Madille76bdda2014-10-20 17:13:52 -04001579bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1580{
1581 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1582}
1583
Geoff Langef7b0162014-09-04 13:29:23 -04001584gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001585{
1586 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1587 ImageD3D *image = mImageArray[faceIndex][level];
1588
1589 if (image->isDirty())
1590 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001591 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1592 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1593 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001594 gl::Error error = commitRegion(index, region);
1595 if (error.isError())
1596 {
1597 return error;
1598 }
Brandon Jones0511e802014-07-14 16:27:26 -07001599 }
Geoff Langef7b0162014-09-04 13:29:23 -04001600
1601 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001602}
1603
1604void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1605{
1606 // If there currently is a corresponding storage texture image, it has these parameters
1607 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1608 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1609 const GLenum storageFormat = getBaseLevelInternalFormat();
1610
1611 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1612
1613 if (mTexStorage)
1614 {
1615 const int storageLevels = mTexStorage->getLevelCount();
1616
1617 if ((level >= storageLevels && storageLevels != 0) ||
1618 width != storageWidth ||
1619 height != storageHeight ||
1620 internalformat != storageFormat) // Discard mismatched storage
1621 {
1622 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1623 {
1624 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1625 {
1626 mImageArray[faceIndex][level]->markDirty();
1627 }
1628 }
1629
1630 SafeDelete(mTexStorage);
1631
1632 mDirtyImages = true;
1633 }
1634 }
1635}
1636
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001637gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1638{
1639 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1640}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001641
Jamie Madillcb83dc12014-09-29 10:46:12 -04001642gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1643{
1644 // The "layer" of the image index corresponds to the cube face
1645 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1646}
1647
Jamie Madill710e5772014-10-20 17:13:53 -04001648bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1649{
1650 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1651 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1652}
1653
Brandon Jones78b1acd2014-07-15 15:33:07 -07001654TextureD3D_3D::TextureD3D_3D(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001655 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001656{
1657 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1658 {
1659 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1660 }
1661}
1662
1663TextureD3D_3D::~TextureD3D_3D()
1664{
Austin Kinross69822602014-08-12 15:51:37 -07001665 // Delete the Images before the TextureStorage.
1666 // Images might be relying on the TextureStorage for some of their data.
1667 // 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 -07001668 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1669 {
1670 delete mImageArray[i];
1671 }
Austin Kinross69822602014-08-12 15:51:37 -07001672
1673 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001674}
1675
Brandon Jonescef06ff2014-08-05 13:27:48 -07001676Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001677{
1678 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001679 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001680 return mImageArray[level];
1681}
1682
Jamie Madillfeda4d22014-09-17 13:03:29 -04001683Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1684{
1685 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001686 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001687 ASSERT(index.type == GL_TEXTURE_3D);
1688 return mImageArray[index.mipIndex];
1689}
1690
Brandon Jonescef06ff2014-08-05 13:27:48 -07001691GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001692{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001693 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1694 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001695}
1696
Brandon Jones78b1acd2014-07-15 15:33:07 -07001697GLsizei TextureD3D_3D::getWidth(GLint level) const
1698{
1699 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1700 return mImageArray[level]->getWidth();
1701 else
1702 return 0;
1703}
1704
1705GLsizei TextureD3D_3D::getHeight(GLint level) const
1706{
1707 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1708 return mImageArray[level]->getHeight();
1709 else
1710 return 0;
1711}
1712
1713GLsizei TextureD3D_3D::getDepth(GLint level) const
1714{
1715 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1716 return mImageArray[level]->getDepth();
1717 else
1718 return 0;
1719}
1720
1721GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1722{
1723 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1724 return mImageArray[level]->getInternalFormat();
1725 else
1726 return GL_NONE;
1727}
1728
1729bool TextureD3D_3D::isDepth(GLint level) const
1730{
Geoff Lang5d601382014-07-22 15:14:06 -04001731 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001732}
1733
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001734gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1735 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1736 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001737{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001738 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001739 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1740
Brandon Jones78b1acd2014-07-15 15:33:07 -07001741 redefineImage(level, sizedInternalFormat, width, height, depth);
1742
1743 bool fastUnpacked = false;
1744
Jamie Madillba6bc952014-10-06 10:56:22 -04001745 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1746
Brandon Jones78b1acd2014-07-15 15:33:07 -07001747 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1748 if (isFastUnpackable(unpack, sizedInternalFormat))
1749 {
1750 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001751 RenderTarget *destRenderTarget = NULL;
1752 gl::Error error = getRenderTarget(index, &destRenderTarget);
1753 if (error.isError())
1754 {
1755 return error;
1756 }
1757
Brandon Jones78b1acd2014-07-15 15:33:07 -07001758 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1759
Geoff Lang64f23f62014-09-10 14:40:12 -04001760 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1761 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001762 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001763 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001764 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001765
1766 // Ensure we don't overwrite our newly initialized data
1767 mImageArray[level]->markClean();
1768
1769 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001770 }
1771
1772 if (!fastUnpacked)
1773 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001774 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001775 if (error.isError())
1776 {
1777 return error;
1778 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001779 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001780
1781 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001782}
1783
Geoff Langb5348332014-09-02 13:16:34 -04001784gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1785 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001786 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001787{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001788 ASSERT(target == GL_TEXTURE_3D);
1789
Brandon Jones78b1acd2014-07-15 15:33:07 -07001790 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1791 redefineImage(level, format, width, height, depth);
1792
Jamie Madillc751d1e2014-10-21 17:46:29 -04001793 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001794}
1795
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001796gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1797 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1798 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001799{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001800 ASSERT(target == GL_TEXTURE_3D);
1801
Brandon Jones78b1acd2014-07-15 15:33:07 -07001802 bool fastUnpacked = false;
1803
Jamie Madillac7579c2014-09-17 16:59:33 -04001804 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1805
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1807 if (isFastUnpackable(unpack, getInternalFormat(level)))
1808 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001809 RenderTarget *destRenderTarget = NULL;
1810 gl::Error error = getRenderTarget(index, &destRenderTarget);
1811 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001812 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001813 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001814 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001815
1816 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1817 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1818 if (error.isError())
1819 {
1820 return error;
1821 }
1822
1823 // Ensure we don't overwrite our newly initialized data
1824 mImageArray[level]->markClean();
1825
1826 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001827 }
1828
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001829 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001830 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001831 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1832 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001833 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001834
1835 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001836}
1837
Geoff Langb5348332014-09-02 13:16:34 -04001838gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1839 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001840 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001841{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001842 ASSERT(target == GL_TEXTURE_3D);
1843
Geoff Langb5348332014-09-02 13:16:34 -04001844 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001845 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001846 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001847 {
Geoff Langb5348332014-09-02 13:16:34 -04001848 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849 }
Geoff Langb5348332014-09-02 13:16:34 -04001850
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001851 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1852 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1853 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001854}
1855
Geoff Langef7b0162014-09-04 13:29:23 -04001856gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1857 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001858{
1859 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001860 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001861}
1862
Geoff Langef7b0162014-09-04 13:29:23 -04001863gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1864 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001865{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001866 ASSERT(target == GL_TEXTURE_3D);
1867
Jamie Madill82bf0c52014-10-03 11:50:53 -04001868 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001869 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001870
Jamie Madille76bdda2014-10-20 17:13:52 -04001871 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001872 {
Geoff Langef7b0162014-09-04 13:29:23 -04001873 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1874 if (error.isError())
1875 {
1876 return error;
1877 }
1878
Brandon Jones78b1acd2014-07-15 15:33:07 -07001879 mDirtyImages = true;
1880 }
1881 else
1882 {
Geoff Langef7b0162014-09-04 13:29:23 -04001883 gl::Error error = ensureRenderTarget();
1884 if (error.isError())
1885 {
1886 return error;
1887 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001888
1889 if (isValidLevel(level))
1890 {
Geoff Langef7b0162014-09-04 13:29:23 -04001891 error = updateStorageLevel(level);
1892 if (error.isError())
1893 {
1894 return error;
1895 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001896
Geoff Langef7b0162014-09-04 13:29:23 -04001897 error = mRenderer->copyImage3D(source, sourceRect,
1898 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1899 xoffset, yoffset, zoffset, mTexStorage, level);
1900 if (error.isError())
1901 {
1902 return error;
1903 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001904 }
1905 }
Geoff Langef7b0162014-09-04 13:29:23 -04001906
1907 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001908}
1909
Geoff Lang1f8532b2014-09-05 09:46:13 -04001910gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001911{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001912 ASSERT(target == GL_TEXTURE_3D);
1913
Brandon Jones78b1acd2014-07-15 15:33:07 -07001914 for (int level = 0; level < levels; level++)
1915 {
1916 GLsizei levelWidth = std::max(1, width >> level);
1917 GLsizei levelHeight = std::max(1, height >> level);
1918 GLsizei levelDepth = std::max(1, depth >> level);
1919 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1920 }
1921
1922 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1923 {
1924 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1925 }
1926
Geoff Lang1f8532b2014-09-05 09:46:13 -04001927 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001928 bool renderTarget = IsRenderTargetUsage(mUsage);
1929 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001930
1931 gl::Error error = setCompleteTexStorage(storage);
1932 if (error.isError())
1933 {
1934 SafeDelete(storage);
1935 return error;
1936 }
1937
1938 mImmutable = true;
1939
1940 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001941}
1942
Brandon Jones6053a522014-07-25 16:22:09 -07001943void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001944{
Brandon Jones6053a522014-07-25 16:22:09 -07001945 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001946}
1947
Brandon Jones6053a522014-07-25 16:22:09 -07001948void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001949{
Brandon Jones6053a522014-07-25 16:22:09 -07001950 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001951}
1952
Brandon Jones6053a522014-07-25 16:22:09 -07001953
Jamie Madill4aa79e12014-09-29 10:46:14 -04001954void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001955{
1956 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1957 int levelCount = mipLevels();
1958 for (int level = 1; level < levelCount; level++)
1959 {
1960 redefineImage(level, getBaseLevelInternalFormat(),
1961 std::max(getBaseLevelWidth() >> level, 1),
1962 std::max(getBaseLevelHeight() >> level, 1),
1963 std::max(getBaseLevelDepth() >> level, 1));
1964 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001965}
1966
Jamie Madillac7579c2014-09-17 16:59:33 -04001967unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001968{
Geoff Langef7b0162014-09-04 13:29:23 -04001969 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001970}
1971
Geoff Lang64f23f62014-09-10 14:40:12 -04001972gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001973{
1974 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001975 gl::Error error = ensureRenderTarget();
1976 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001977 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001978 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001979 }
1980
Jamie Madillac7579c2014-09-17 16:59:33 -04001981 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001982 {
Geoff Langef7b0162014-09-04 13:29:23 -04001983 error = updateStorage();
1984 if (error.isError())
1985 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001986 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001987 }
Jamie Madillac7579c2014-09-17 16:59:33 -04001988 }
1989 else
1990 {
Geoff Langef7b0162014-09-04 13:29:23 -04001991 error = updateStorageLevel(index.mipIndex);
1992 if (error.isError())
1993 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001994 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001995 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001996 }
1997
Geoff Lang64f23f62014-09-10 14:40:12 -04001998 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001999}
2000
Geoff Langef7b0162014-09-04 13:29:23 -04002001gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002002{
2003 // Only initialize the first time this texture is used as a render target or shader resource
2004 if (mTexStorage)
2005 {
Geoff Langef7b0162014-09-04 13:29:23 -04002006 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002007 }
2008
2009 // do not attempt to create storage for nonexistant data
2010 if (!isLevelComplete(0))
2011 {
Geoff Langef7b0162014-09-04 13:29:23 -04002012 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002013 }
2014
2015 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2016
Geoff Langef7b0162014-09-04 13:29:23 -04002017 rx::TextureStorage *storage = NULL;
2018 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2019 if (error.isError())
2020 {
2021 return error;
2022 }
2023
2024 error = setCompleteTexStorage(storage);
2025 if (error.isError())
2026 {
2027 SafeDelete(storage);
2028 return error;
2029 }
2030
Brandon Jones78b1acd2014-07-15 15:33:07 -07002031 ASSERT(mTexStorage);
2032
2033 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002034 error = updateStorage();
2035 if (error.isError())
2036 {
2037 return error;
2038 }
2039
2040 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002041}
2042
Geoff Langef7b0162014-09-04 13:29:23 -04002043gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002044{
2045 GLsizei width = getBaseLevelWidth();
2046 GLsizei height = getBaseLevelHeight();
2047 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002048 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002049
2050 ASSERT(width > 0 && height > 0 && depth > 0);
2051
2052 // use existing storage level count, when previously specified by TexStorage*D
2053 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2054
Geoff Langef7b0162014-09-04 13:29:23 -04002055 // TODO: Verify creation of the storage succeeded
2056 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2057
2058 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002059}
2060
Geoff Langef7b0162014-09-04 13:29:23 -04002061gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002062{
2063 SafeDelete(mTexStorage);
2064 mTexStorage = newCompleteTexStorage;
2065 mDirtyImages = true;
2066
2067 // We do not support managed 3D storage, as that is D3D9/ES2-only
2068 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002069
2070 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002071}
2072
Geoff Langef7b0162014-09-04 13:29:23 -04002073gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002074{
2075 ASSERT(mTexStorage != NULL);
2076 GLint storageLevels = mTexStorage->getLevelCount();
2077 for (int level = 0; level < storageLevels; level++)
2078 {
2079 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2080 {
Geoff Langef7b0162014-09-04 13:29:23 -04002081 gl::Error error = updateStorageLevel(level);
2082 if (error.isError())
2083 {
2084 return error;
2085 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002086 }
2087 }
Geoff Langef7b0162014-09-04 13:29:23 -04002088
2089 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002090}
2091
Brandon Jones78b1acd2014-07-15 15:33:07 -07002092bool TextureD3D_3D::isValidLevel(int level) const
2093{
2094 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2095}
2096
2097bool TextureD3D_3D::isLevelComplete(int level) const
2098{
2099 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2100
2101 if (isImmutable())
2102 {
2103 return true;
2104 }
2105
2106 GLsizei width = getBaseLevelWidth();
2107 GLsizei height = getBaseLevelHeight();
2108 GLsizei depth = getBaseLevelDepth();
2109
2110 if (width <= 0 || height <= 0 || depth <= 0)
2111 {
2112 return false;
2113 }
2114
2115 if (level == 0)
2116 {
2117 return true;
2118 }
2119
2120 ImageD3D *levelImage = mImageArray[level];
2121
2122 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2123 {
2124 return false;
2125 }
2126
2127 if (levelImage->getWidth() != std::max(1, width >> level))
2128 {
2129 return false;
2130 }
2131
2132 if (levelImage->getHeight() != std::max(1, height >> level))
2133 {
2134 return false;
2135 }
2136
2137 if (levelImage->getDepth() != std::max(1, depth >> level))
2138 {
2139 return false;
2140 }
2141
2142 return true;
2143}
2144
Jamie Madille76bdda2014-10-20 17:13:52 -04002145bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2146{
2147 return isLevelComplete(index.mipIndex);
2148}
2149
Geoff Langef7b0162014-09-04 13:29:23 -04002150gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002151{
2152 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2153 ASSERT(isLevelComplete(level));
2154
2155 if (mImageArray[level]->isDirty())
2156 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002157 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2158 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002159 gl::Error error = commitRegion(index, region);
2160 if (error.isError())
2161 {
2162 return error;
2163 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002164 }
Geoff Langef7b0162014-09-04 13:29:23 -04002165
2166 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002167}
2168
2169void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2170{
2171 // If there currently is a corresponding storage texture image, it has these parameters
2172 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2173 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2174 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2175 const GLenum storageFormat = getBaseLevelInternalFormat();
2176
2177 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2178
2179 if (mTexStorage)
2180 {
2181 const int storageLevels = mTexStorage->getLevelCount();
2182
2183 if ((level >= storageLevels && storageLevels != 0) ||
2184 width != storageWidth ||
2185 height != storageHeight ||
2186 depth != storageDepth ||
2187 internalformat != storageFormat) // Discard mismatched storage
2188 {
2189 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2190 {
2191 mImageArray[i]->markDirty();
2192 }
2193
2194 SafeDelete(mTexStorage);
2195 mDirtyImages = true;
2196 }
2197 }
2198}
2199
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002200gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2201{
2202 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2203 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2204}
Brandon Jones142ec422014-07-16 10:31:30 -07002205
Jamie Madillcb83dc12014-09-29 10:46:12 -04002206gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2207{
2208 // The "layer" here does not apply to 3D images. We use one Image per mip.
2209 return gl::ImageIndex::Make3D(mip);
2210}
2211
Jamie Madill710e5772014-10-20 17:13:53 -04002212bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2213{
2214 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2215 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2216}
2217
Brandon Jones142ec422014-07-16 10:31:30 -07002218TextureD3D_2DArray::TextureD3D_2DArray(Renderer *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002219 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002220{
2221 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2222 {
2223 mLayerCounts[level] = 0;
2224 mImageArray[level] = NULL;
2225 }
2226}
2227
2228TextureD3D_2DArray::~TextureD3D_2DArray()
2229{
Austin Kinross69822602014-08-12 15:51:37 -07002230 // Delete the Images before the TextureStorage.
2231 // Images might be relying on the TextureStorage for some of their data.
2232 // 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 -07002233 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002234 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002235}
2236
Brandon Jones142ec422014-07-16 10:31:30 -07002237Image *TextureD3D_2DArray::getImage(int level, int layer) const
2238{
2239 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2240 ASSERT(layer < mLayerCounts[level]);
2241 return mImageArray[level][layer];
2242}
2243
Jamie Madillfeda4d22014-09-17 13:03:29 -04002244Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2245{
2246 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2247 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2248 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2249 return mImageArray[index.mipIndex][index.layerIndex];
2250}
2251
Brandon Jones142ec422014-07-16 10:31:30 -07002252GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2253{
2254 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2255 return mLayerCounts[level];
2256}
2257
Brandon Jones142ec422014-07-16 10:31:30 -07002258GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2259{
2260 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2261}
2262
2263GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2264{
2265 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2266}
2267
Brandon Jones142ec422014-07-16 10:31:30 -07002268GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2269{
2270 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2271}
2272
2273bool TextureD3D_2DArray::isDepth(GLint level) const
2274{
Geoff Lang5d601382014-07-22 15:14:06 -04002275 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002276}
2277
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002278gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2279 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2280 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002281{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002282 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2283
Geoff Lang5d601382014-07-22 15:14:06 -04002284 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2285
Brandon Jones142ec422014-07-16 10:31:30 -07002286 redefineImage(level, sizedInternalFormat, width, height, depth);
2287
Geoff Lang5d601382014-07-22 15:14:06 -04002288 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2289 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002290
2291 for (int i = 0; i < depth; i++)
2292 {
2293 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002294 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2295 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002296 if (error.isError())
2297 {
2298 return error;
2299 }
Brandon Jones142ec422014-07-16 10:31:30 -07002300 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002301
2302 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002303}
2304
Geoff Langb5348332014-09-02 13:16:34 -04002305gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2306 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002307 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002308{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002309 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2310
Brandon Jones142ec422014-07-16 10:31:30 -07002311 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2312 redefineImage(level, format, width, height, depth);
2313
Geoff Lang5d601382014-07-22 15:14:06 -04002314 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2315 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002316
2317 for (int i = 0; i < depth; i++)
2318 {
2319 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002320 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002321 if (error.isError())
2322 {
2323 return error;
2324 }
Brandon Jones142ec422014-07-16 10:31:30 -07002325 }
Geoff Langb5348332014-09-02 13:16:34 -04002326
2327 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002328}
2329
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002330gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2331 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2332 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002333{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002334 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2335
Geoff Lang5d601382014-07-22 15:14:06 -04002336 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2337 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002338
2339 for (int i = 0; i < depth; i++)
2340 {
2341 int layer = zoffset + i;
2342 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2343
Jamie Madillfeda4d22014-09-17 13:03:29 -04002344 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002345 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2346 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002347 if (error.isError())
2348 {
2349 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002350 }
2351 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002352
2353 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002354}
2355
Geoff Langb5348332014-09-02 13:16:34 -04002356gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2357 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002358 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002359{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002360 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2361
Geoff Lang5d601382014-07-22 15:14:06 -04002362 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2363 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002364
2365 for (int i = 0; i < depth; i++)
2366 {
2367 int layer = zoffset + i;
2368 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2369
Jamie Madillc751d1e2014-10-21 17:46:29 -04002370 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, unpack, layerPixels, mImageArray[level][layer]);
Geoff Langb5348332014-09-02 13:16:34 -04002371 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002372 {
Geoff Langb5348332014-09-02 13:16:34 -04002373 return error;
2374 }
2375
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002376 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2377 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2378 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002379 if (error.isError())
2380 {
2381 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002382 }
2383 }
Geoff Langb5348332014-09-02 13:16:34 -04002384
2385 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002386}
2387
Geoff Langef7b0162014-09-04 13:29:23 -04002388gl::Error TextureD3D_2DArray::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07002389{
2390 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002391 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002392}
2393
Geoff Langef7b0162014-09-04 13:29:23 -04002394gl::Error TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones142ec422014-07-16 10:31:30 -07002395{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002396 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2397
Jamie Madill82bf0c52014-10-03 11:50:53 -04002398 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002399 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002400
Jamie Madille76bdda2014-10-20 17:13:52 -04002401 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002402 {
Geoff Langef7b0162014-09-04 13:29:23 -04002403 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2404 if (error.isError())
2405 {
2406 return error;
2407 }
2408
Brandon Jones142ec422014-07-16 10:31:30 -07002409 mDirtyImages = true;
2410 }
2411 else
2412 {
Geoff Langef7b0162014-09-04 13:29:23 -04002413 gl::Error error = ensureRenderTarget();
2414 if (error.isError())
2415 {
2416 return error;
2417 }
Brandon Jones142ec422014-07-16 10:31:30 -07002418
2419 if (isValidLevel(level))
2420 {
Geoff Langef7b0162014-09-04 13:29:23 -04002421 error = updateStorageLevel(level);
2422 if (error.isError())
2423 {
2424 return error;
2425 }
Brandon Jones142ec422014-07-16 10:31:30 -07002426
Geoff Langef7b0162014-09-04 13:29:23 -04002427 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2428 xoffset, yoffset, zoffset, mTexStorage, level);
2429 if (error.isError())
2430 {
2431 return error;
2432 }
Brandon Jones142ec422014-07-16 10:31:30 -07002433 }
2434 }
Geoff Langef7b0162014-09-04 13:29:23 -04002435 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002436}
2437
Geoff Lang1f8532b2014-09-05 09:46:13 -04002438gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002439{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002440 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2441
Brandon Jones142ec422014-07-16 10:31:30 -07002442 deleteImages();
2443
2444 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2445 {
2446 GLsizei levelWidth = std::max(1, width >> level);
2447 GLsizei levelHeight = std::max(1, height >> level);
2448
2449 mLayerCounts[level] = (level < levels ? depth : 0);
2450
2451 if (mLayerCounts[level] > 0)
2452 {
2453 // Create new images for this level
2454 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2455
2456 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2457 {
2458 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2459 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2460 levelHeight, 1, true);
2461 }
2462 }
2463 }
2464
Geoff Lang1f8532b2014-09-05 09:46:13 -04002465 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002466 bool renderTarget = IsRenderTargetUsage(mUsage);
2467 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002468
2469 gl::Error error = setCompleteTexStorage(storage);
2470 if (error.isError())
2471 {
2472 SafeDelete(storage);
2473 return error;
2474 }
2475
2476 mImmutable = true;
2477
2478 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002479}
2480
Brandon Jones6053a522014-07-25 16:22:09 -07002481void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002482{
Brandon Jones6053a522014-07-25 16:22:09 -07002483 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002484}
2485
Brandon Jones6053a522014-07-25 16:22:09 -07002486void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002487{
Brandon Jones6053a522014-07-25 16:22:09 -07002488 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002489}
2490
Brandon Jones6053a522014-07-25 16:22:09 -07002491
Jamie Madill4aa79e12014-09-29 10:46:14 -04002492void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002493{
2494 int baseWidth = getBaseLevelWidth();
2495 int baseHeight = getBaseLevelHeight();
2496 int baseDepth = getBaseLevelDepth();
2497 GLenum baseFormat = getBaseLevelInternalFormat();
2498
2499 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2500 int levelCount = mipLevels();
2501 for (int level = 1; level < levelCount; level++)
2502 {
2503 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2504 }
Brandon Jones142ec422014-07-16 10:31:30 -07002505}
2506
Jamie Madillac7579c2014-09-17 16:59:33 -04002507unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002508{
Geoff Langef7b0162014-09-04 13:29:23 -04002509 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002510}
2511
Geoff Lang64f23f62014-09-10 14:40:12 -04002512gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002513{
2514 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002515 gl::Error error = ensureRenderTarget();
2516 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002517 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002518 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002519 }
2520
Geoff Langef7b0162014-09-04 13:29:23 -04002521 error = updateStorageLevel(index.mipIndex);
2522 if (error.isError())
2523 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002524 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002525 }
2526
Geoff Lang64f23f62014-09-10 14:40:12 -04002527 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002528}
2529
Geoff Langef7b0162014-09-04 13:29:23 -04002530gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002531{
2532 // Only initialize the first time this texture is used as a render target or shader resource
2533 if (mTexStorage)
2534 {
Geoff Langef7b0162014-09-04 13:29:23 -04002535 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002536 }
2537
2538 // do not attempt to create storage for nonexistant data
2539 if (!isLevelComplete(0))
2540 {
Geoff Langef7b0162014-09-04 13:29:23 -04002541 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002542 }
2543
2544 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2545
Geoff Langef7b0162014-09-04 13:29:23 -04002546 TextureStorage *storage = NULL;
2547 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2548 if (error.isError())
2549 {
2550 return error;
2551 }
2552
2553 error = setCompleteTexStorage(storage);
2554 if (error.isError())
2555 {
2556 SafeDelete(storage);
2557 return error;
2558 }
2559
Brandon Jones142ec422014-07-16 10:31:30 -07002560 ASSERT(mTexStorage);
2561
2562 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002563 error = updateStorage();
2564 if (error.isError())
2565 {
2566 return error;
2567 }
2568
2569 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002570}
2571
Geoff Langef7b0162014-09-04 13:29:23 -04002572gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002573{
2574 GLsizei width = getBaseLevelWidth();
2575 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002576 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002577 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002578
2579 ASSERT(width > 0 && height > 0 && depth > 0);
2580
2581 // use existing storage level count, when previously specified by TexStorage*D
2582 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2583
Geoff Langef7b0162014-09-04 13:29:23 -04002584 // TODO(geofflang): Verify storage creation succeeds
2585 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2586
2587 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002588}
2589
Geoff Langef7b0162014-09-04 13:29:23 -04002590gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002591{
2592 SafeDelete(mTexStorage);
2593 mTexStorage = newCompleteTexStorage;
2594 mDirtyImages = true;
2595
2596 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2597 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002598
2599 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002600}
2601
Geoff Langef7b0162014-09-04 13:29:23 -04002602gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002603{
2604 ASSERT(mTexStorage != NULL);
2605 GLint storageLevels = mTexStorage->getLevelCount();
2606 for (int level = 0; level < storageLevels; level++)
2607 {
2608 if (isLevelComplete(level))
2609 {
Geoff Langef7b0162014-09-04 13:29:23 -04002610 gl::Error error = updateStorageLevel(level);
2611 if (error.isError())
2612 {
2613 return error;
2614 }
Brandon Jones142ec422014-07-16 10:31:30 -07002615 }
2616 }
Geoff Langef7b0162014-09-04 13:29:23 -04002617
2618 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002619}
2620
Brandon Jones142ec422014-07-16 10:31:30 -07002621bool TextureD3D_2DArray::isValidLevel(int level) const
2622{
2623 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2624}
2625
2626bool TextureD3D_2DArray::isLevelComplete(int level) const
2627{
2628 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2629
2630 if (isImmutable())
2631 {
2632 return true;
2633 }
2634
2635 GLsizei width = getBaseLevelWidth();
2636 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002637 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002638
2639 if (width <= 0 || height <= 0 || layers <= 0)
2640 {
2641 return false;
2642 }
2643
2644 if (level == 0)
2645 {
2646 return true;
2647 }
2648
2649 if (getInternalFormat(level) != getInternalFormat(0))
2650 {
2651 return false;
2652 }
2653
2654 if (getWidth(level) != std::max(1, width >> level))
2655 {
2656 return false;
2657 }
2658
2659 if (getHeight(level) != std::max(1, height >> level))
2660 {
2661 return false;
2662 }
2663
Jamie Madill3269bcb2014-09-30 16:33:52 -04002664 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002665 {
2666 return false;
2667 }
2668
2669 return true;
2670}
2671
Jamie Madille76bdda2014-10-20 17:13:52 -04002672bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2673{
2674 return isLevelComplete(index.mipIndex);
2675}
2676
Geoff Langef7b0162014-09-04 13:29:23 -04002677gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002678{
2679 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2680 ASSERT(isLevelComplete(level));
2681
2682 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2683 {
2684 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2685 if (mImageArray[level][layer]->isDirty())
2686 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002687 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2688 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002689 gl::Error error = commitRegion(index, region);
2690 if (error.isError())
2691 {
2692 return error;
2693 }
Brandon Jones142ec422014-07-16 10:31:30 -07002694 }
2695 }
Geoff Langef7b0162014-09-04 13:29:23 -04002696
2697 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002698}
2699
2700void TextureD3D_2DArray::deleteImages()
2701{
2702 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2703 {
2704 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2705 {
2706 delete mImageArray[level][layer];
2707 }
2708 delete[] mImageArray[level];
2709 mImageArray[level] = NULL;
2710 mLayerCounts[level] = 0;
2711 }
2712}
2713
2714void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2715{
2716 // If there currently is a corresponding storage texture image, it has these parameters
2717 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2718 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002719 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002720 const GLenum storageFormat = getBaseLevelInternalFormat();
2721
2722 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2723 {
2724 delete mImageArray[level][layer];
2725 }
2726 delete[] mImageArray[level];
2727 mImageArray[level] = NULL;
2728 mLayerCounts[level] = depth;
2729
2730 if (depth > 0)
2731 {
2732 mImageArray[level] = new ImageD3D*[depth]();
2733
2734 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2735 {
2736 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2737 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2738 }
2739 }
2740
2741 if (mTexStorage)
2742 {
2743 const int storageLevels = mTexStorage->getLevelCount();
2744
2745 if ((level >= storageLevels && storageLevels != 0) ||
2746 width != storageWidth ||
2747 height != storageHeight ||
2748 depth != storageDepth ||
2749 internalformat != storageFormat) // Discard mismatched storage
2750 {
2751 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2752 {
2753 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2754 {
2755 mImageArray[level][layer]->markDirty();
2756 }
2757 }
2758
2759 delete mTexStorage;
2760 mTexStorage = NULL;
2761 mDirtyImages = true;
2762 }
2763 }
2764}
2765
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002766gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2767{
2768 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2769}
2770
Jamie Madillcb83dc12014-09-29 10:46:12 -04002771gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2772{
2773 return gl::ImageIndex::Make2DArray(mip, layer);
2774}
2775
Jamie Madill710e5772014-10-20 17:13:53 -04002776bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2777{
2778 // Check for having a storage and the right type of index
2779 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2780 {
2781 return false;
2782 }
2783
2784 // Check the mip index
2785 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2786 {
2787 return false;
2788 }
2789
2790 // Check the layer index
2791 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2792}
2793
Brandon Jones78b1acd2014-07-15 15:33:07 -07002794}