blob: 4a67701fdf614b728063991b1802bb5d907b5f55 [file] [log] [blame]
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001//
2// Copyright 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// TextureD3D.cpp: Implementations of the Texture interfaces shared betweeen the D3D backends.
8
Jamie Madill93e13fb2014-11-06 15:27:25 -05009#include "libGLESv2/Buffer.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070010#include "libGLESv2/Framebuffer.h"
Brandon Jonescef06ff2014-08-05 13:27:48 -070011#include "libGLESv2/Texture.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070012#include "libGLESv2/main.h"
13#include "libGLESv2/formatutils.h"
14#include "libGLESv2/renderer/BufferImpl.h"
15#include "libGLESv2/renderer/RenderTarget.h"
Jamie Madill93e13fb2014-11-06 15:27:25 -050016#include "libGLESv2/renderer/d3d/BufferD3D.h"
17#include "libGLESv2/renderer/d3d/TextureD3D.h"
18#include "libGLESv2/renderer/d3d/TextureStorage.h"
19#include "libGLESv2/renderer/d3d/ImageD3D.h"
20#include "libGLESv2/renderer/d3d/RendererD3D.h"
Geoff Lang0b7eef72014-06-12 14:10:47 -040021
22#include "libEGL/Surface.h"
23
24#include "common/mathutil.h"
25#include "common/utilities.h"
Brandon Jonesf47bebc2014-07-09 14:28:42 -070026
27namespace rx
28{
29
Jamie Madillc751d1e2014-10-21 17:46:29 -040030namespace
31{
32
33gl::Error GetUnpackPointer(const gl::PixelUnpackState &unpack, const void *pixels, const uint8_t **pointerOut)
34{
35 if (unpack.pixelBuffer.id() != 0)
36 {
37 // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
38 gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
39 ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
40
41 // TODO: this is the only place outside of renderer that asks for a buffers raw data.
42 // This functionality should be moved into renderer and the getData method of BufferImpl removed.
Jamie Madill9ae396b2014-10-21 17:46:30 -040043 BufferD3D *bufferD3D = BufferD3D::makeBufferD3D(pixelBuffer->getImplementation());
44 ASSERT(bufferD3D);
Jamie Madillc751d1e2014-10-21 17:46:29 -040045 const uint8_t *bufferData = NULL;
Jamie Madill9ae396b2014-10-21 17:46:30 -040046 gl::Error error = bufferD3D->getData(&bufferData);
Jamie Madillc751d1e2014-10-21 17:46:29 -040047 if (error.isError())
48 {
49 return error;
50 }
51
52 *pointerOut = bufferData + offset;
53 }
54 else
55 {
56 *pointerOut = static_cast<const uint8_t *>(pixels);
57 }
58
59 return gl::Error(GL_NO_ERROR);
60}
61
Brandon Jonesf47bebc2014-07-09 14:28:42 -070062bool IsRenderTargetUsage(GLenum usage)
63{
64 return (usage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
65}
66
Jamie Madillc751d1e2014-10-21 17:46:29 -040067}
68
Jamie Madill93e13fb2014-11-06 15:27:25 -050069TextureD3D::TextureD3D(RendererD3D *renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070070 : mRenderer(renderer),
71 mUsage(GL_NONE),
72 mDirtyImages(true),
Jamie Madill98553e32014-09-30 16:33:50 -040073 mImmutable(false),
74 mTexStorage(NULL)
Brandon Jonesf47bebc2014-07-09 14:28:42 -070075{
76}
77
78TextureD3D::~TextureD3D()
79{
80}
81
Brandon Jones6053a522014-07-25 16:22:09 -070082TextureD3D *TextureD3D::makeTextureD3D(TextureImpl *texture)
83{
84 ASSERT(HAS_DYNAMIC_TYPE(TextureD3D*, texture));
85 return static_cast<TextureD3D*>(texture);
86}
87
Jamie Madill2f06dbf2014-09-18 15:08:50 -040088TextureStorage *TextureD3D::getNativeTexture()
Brandon Jones6053a522014-07-25 16:22:09 -070089{
90 // ensure the underlying texture is created
91 initializeStorage(false);
92
Jamie Madill98553e32014-09-30 16:33:50 -040093 if (mTexStorage)
Brandon Jones6053a522014-07-25 16:22:09 -070094 {
95 updateStorage();
96 }
97
Jamie Madill98553e32014-09-30 16:33:50 -040098 return mTexStorage;
Brandon Jones6053a522014-07-25 16:22:09 -070099}
100
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700101GLint TextureD3D::getBaseLevelWidth() const
102{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700103 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700104 return (baseImage ? baseImage->getWidth() : 0);
105}
106
107GLint TextureD3D::getBaseLevelHeight() const
108{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700109 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700110 return (baseImage ? baseImage->getHeight() : 0);
111}
112
113GLint TextureD3D::getBaseLevelDepth() const
114{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700115 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700116 return (baseImage ? baseImage->getDepth() : 0);
117}
118
119// Note: "base level image" is loosely defined to be any image from the base level,
120// where in the base of 2D array textures and cube maps there are several. Don't use
121// the base level image for anything except querying texture format and size.
122GLenum TextureD3D::getBaseLevelInternalFormat() const
123{
Brandon Jones78b1acd2014-07-15 15:33:07 -0700124 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700125 return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
126}
127
Jamie Madillec6de4e2014-10-20 10:59:56 -0400128bool TextureD3D::shouldUseSetData(const Image *image) const
129{
130 if (!mRenderer->getWorkarounds().setDataFasterThanImageUpload)
131 {
132 return false;
133 }
134
135 gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
136
137 // We can only handle full updates for depth-stencil textures, so to avoid complications
138 // disable them entirely.
139 if (internalFormat.depthBits > 0 || internalFormat.stencilBits > 0)
140 {
141 return false;
142 }
143
144 // TODO(jmadill): Handle compressed internal formats
145 return (mTexStorage && !internalFormat.compressed);
146}
147
Jamie Madillba6bc952014-10-06 10:56:22 -0400148gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700149{
Jamie Madillba6bc952014-10-06 10:56:22 -0400150 Image *image = getImage(index);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400151 ASSERT(image);
Jamie Madillba6bc952014-10-06 10:56:22 -0400152
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700153 // No-op
154 if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
155 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400156 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700157 }
158
159 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
160 // 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 -0400161 const uint8_t *pixelData = NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -0400162 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
163 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700164 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400165 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700166 }
167
168 if (pixelData != NULL)
169 {
Jamie Madill9aca0592014-10-06 16:26:59 -0400170 gl::Error error(GL_NO_ERROR);
171
Jamie Madillec6de4e2014-10-20 10:59:56 -0400172 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400173 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400174 error = mTexStorage->setData(index, image, NULL, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400175 }
176 else
177 {
178 error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
179 }
180
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400181 if (error.isError())
182 {
183 return error;
184 }
185
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700186 mDirtyImages = true;
187 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400188
189 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700190}
191
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400192gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
193 GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700194{
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700195 // CPU readback & copy where direct GPU copy is not supported
Jamie Madillc751d1e2014-10-21 17:46:29 -0400196 const uint8_t *pixelData = NULL;
197 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
198 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700199 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400200 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700201 }
202
203 if (pixelData != NULL)
204 {
Jamie Madillfeda4d22014-09-17 13:03:29 -0400205 Image *image = getImage(index);
206 ASSERT(image);
207
Jamie Madill9aca0592014-10-06 16:26:59 -0400208 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
Jamie Madillec6de4e2014-10-20 10:59:56 -0400209 if (shouldUseSetData(image))
Jamie Madill9aca0592014-10-06 16:26:59 -0400210 {
Jamie Madillec6de4e2014-10-20 10:59:56 -0400211 return mTexStorage->setData(index, image, &region, type, unpack, pixelData);
Jamie Madill9aca0592014-10-06 16:26:59 -0400212 }
213
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400214 gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
215 type, pixelData);
216 if (error.isError())
217 {
218 return error;
219 }
220
Jamie Madille6b6da02014-10-02 11:03:14 -0400221 error = commitRegion(index, region);
222 if (error.isError())
223 {
224 return error;
225 }
226
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700227 mDirtyImages = true;
228 }
229
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400230 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700231}
232
Jamie Madillc751d1e2014-10-21 17:46:29 -0400233gl::Error TextureD3D::setCompressedImage(const gl::PixelUnpackState &unpack, GLsizei imageSize, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700234{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400235 // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
236 // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
237 const uint8_t *pixelData = NULL;
238 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
239 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700240 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400241 return error;
242 }
243
244 if (pixelData != NULL)
245 {
246 gl::Error error = image->loadCompressedData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400247 if (error.isError())
248 {
249 return error;
250 }
251
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700252 mDirtyImages = true;
253 }
Geoff Langb5348332014-09-02 13:16:34 -0400254
255 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700256}
257
Geoff Langb5348332014-09-02 13:16:34 -0400258gl::Error TextureD3D::subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400259 GLenum format, GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels, Image *image)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700260{
Jamie Madillc751d1e2014-10-21 17:46:29 -0400261 const uint8_t *pixelData = NULL;
262 gl::Error error = GetUnpackPointer(unpack, pixels, &pixelData);
263 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700264 {
Jamie Madillc751d1e2014-10-21 17:46:29 -0400265 return error;
266 }
267
268 if (pixelData != NULL)
269 {
270 gl::Error error = image->loadCompressedData(xoffset, yoffset, zoffset, width, height, depth, pixelData);
Geoff Langb5348332014-09-02 13:16:34 -0400271 if (error.isError())
272 {
273 return error;
274 }
275
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700276 mDirtyImages = true;
277 }
278
Geoff Langb5348332014-09-02 13:16:34 -0400279 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700280}
281
282bool TextureD3D::isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat)
283{
284 return unpack.pixelBuffer.id() != 0 && mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat);
285}
286
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400287gl::Error TextureD3D::fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
288 GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700289{
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400290 // No-op
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700291 if (destArea.width <= 0 && destArea.height <= 0 && destArea.depth <= 0)
292 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400293 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700294 }
295
296 // In order to perform the fast copy through the shader, we must have the right format, and be able
297 // to create a render target.
298 ASSERT(mRenderer->supportsFastCopyBufferToTexture(sizedInternalFormat));
299
Jacek Cabana5521de2014-10-01 17:23:46 +0200300 uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700301
Geoff Langae5122c2014-08-27 14:08:43 -0400302 gl::Error error = mRenderer->fastCopyBufferToTexture(unpack, offset, destRenderTarget, sizedInternalFormat, type, destArea);
303 if (error.isError())
304 {
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400305 return error;
Geoff Langae5122c2014-08-27 14:08:43 -0400306 }
307
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400308 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700309}
310
311GLint TextureD3D::creationLevels(GLsizei width, GLsizei height, GLsizei depth) const
312{
313 if ((gl::isPow2(width) && gl::isPow2(height) && gl::isPow2(depth)) || mRenderer->getRendererExtensions().textureNPOT)
314 {
315 // Maximum number of levels
316 return gl::log2(std::max(std::max(width, height), depth)) + 1;
317 }
318 else
319 {
320 // OpenGL ES 2.0 without GL_OES_texture_npot does not permit NPOT mipmaps.
321 return 1;
322 }
323}
324
325int TextureD3D::mipLevels() const
326{
327 return gl::log2(std::max(std::max(getBaseLevelWidth(), getBaseLevelHeight()), getBaseLevelDepth())) + 1;
328}
329
Jamie Madill98553e32014-09-30 16:33:50 -0400330TextureStorage *TextureD3D::getStorage()
331{
Jamie Madilldd3bf522014-10-20 17:04:35 -0400332 ASSERT(mTexStorage);
Jamie Madill98553e32014-09-30 16:33:50 -0400333 return mTexStorage;
334}
335
Jamie Madill3269bcb2014-09-30 16:33:52 -0400336Image *TextureD3D::getBaseLevelImage() const
337{
338 return getImage(getImageIndex(0, 0));
339}
340
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400341gl::Error TextureD3D::generateMipmaps()
Jamie Madill4aa79e12014-09-29 10:46:14 -0400342{
Jamie Madill9aca0592014-10-06 16:26:59 -0400343 GLint mipCount = mipLevels();
344
345 if (mipCount == 1)
346 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400347 return gl::Error(GL_NO_ERROR); // no-op
Jamie Madill9aca0592014-10-06 16:26:59 -0400348 }
349
350 // Set up proper mipmap chain in our Image array.
Jamie Madill4aa79e12014-09-29 10:46:14 -0400351 initMipmapsImages();
352
353 // We know that all layers have the same dimension, for the texture to be complete
354 GLint layerCount = static_cast<GLint>(getLayerCount(0));
Jamie Madill4aa79e12014-09-29 10:46:14 -0400355
Jamie Madill9aca0592014-10-06 16:26:59 -0400356 // When making mipmaps with the setData workaround enabled, the texture storage has
357 // the image data already. For non-render-target storage, we have to pull it out into
358 // an image layer.
359 if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
360 {
361 if (!mTexStorage->isRenderTarget())
362 {
363 // Copy from the storage mip 0 to Image mip 0
364 for (GLint layer = 0; layer < layerCount; ++layer)
365 {
366 gl::ImageIndex srcIndex = getImageIndex(0, layer);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400367
Jamie Madill9aca0592014-10-06 16:26:59 -0400368 Image *image = getImage(srcIndex);
369 gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400370 gl::Error error = image->copy(0, 0, 0, area, srcIndex, mTexStorage);
371 if (error.isError())
372 {
373 return error;
374 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400375 }
376 }
377 else
378 {
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400379 gl::Error error = updateStorage();
380 if (error.isError())
381 {
382 return error;
383 }
Jamie Madill9aca0592014-10-06 16:26:59 -0400384 }
385 }
386
387 bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
Jamie Madill4aa79e12014-09-29 10:46:14 -0400388
389 for (GLint layer = 0; layer < layerCount; ++layer)
390 {
391 for (GLint mip = 1; mip < mipCount; ++mip)
392 {
393 ASSERT(getLayerCount(mip) == layerCount);
394
395 gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
396 gl::ImageIndex destIndex = getImageIndex(mip, layer);
397
398 if (renderableStorage)
399 {
400 // GPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400401 gl::Error error = mTexStorage->generateMipmap(sourceIndex, destIndex);
402 if (error.isError())
403 {
404 return error;
405 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400406 }
407 else
408 {
409 // CPU-side mipmapping
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400410 gl::Error error = mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
411 if (error.isError())
412 {
413 return error;
414 }
Jamie Madill4aa79e12014-09-29 10:46:14 -0400415 }
416 }
417 }
Geoff Lang06ecf3d2014-09-23 16:39:50 -0400418
419 return gl::Error(GL_NO_ERROR);
Jamie Madill4aa79e12014-09-29 10:46:14 -0400420}
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700421
Jamie Madill135570a2014-09-30 16:33:51 -0400422bool TextureD3D::isBaseImageZeroSize() const
423{
Jamie Madill3269bcb2014-09-30 16:33:52 -0400424 Image *baseImage = getBaseLevelImage();
Jamie Madill135570a2014-09-30 16:33:51 -0400425
426 if (!baseImage || baseImage->getWidth() <= 0)
427 {
428 return true;
429 }
430
431 if (!gl::IsCubemapTextureTarget(baseImage->getTarget()) && baseImage->getHeight() <= 0)
432 {
433 return true;
434 }
435
436 if (baseImage->getTarget() == GL_TEXTURE_3D && baseImage->getDepth() <= 0)
437 {
438 return true;
439 }
440
441 if (baseImage->getTarget() == GL_TEXTURE_2D_ARRAY && getLayerCount(0) <= 0)
442 {
443 return true;
444 }
445
446 return false;
447}
448
Geoff Langef7b0162014-09-04 13:29:23 -0400449gl::Error TextureD3D::ensureRenderTarget()
Jamie Madill135570a2014-09-30 16:33:51 -0400450{
Geoff Langef7b0162014-09-04 13:29:23 -0400451 gl::Error error = initializeStorage(true);
452 if (error.isError())
453 {
454 return error;
455 }
Jamie Madill135570a2014-09-30 16:33:51 -0400456
457 if (!isBaseImageZeroSize())
458 {
459 ASSERT(mTexStorage);
460 if (!mTexStorage->isRenderTarget())
461 {
Geoff Langef7b0162014-09-04 13:29:23 -0400462 TextureStorage *newRenderTargetStorage = NULL;
463 error = createCompleteStorage(true, &newRenderTargetStorage);
464 if (error.isError())
Jamie Madill135570a2014-09-30 16:33:51 -0400465 {
Geoff Langef7b0162014-09-04 13:29:23 -0400466 return error;
Jamie Madill135570a2014-09-30 16:33:51 -0400467 }
468
Geoff Langef7b0162014-09-04 13:29:23 -0400469 error = mTexStorage->copyToStorage(newRenderTargetStorage);
470 if (error.isError())
471 {
472 SafeDelete(newRenderTargetStorage);
473 return error;
474 }
475
476 error = setCompleteTexStorage(newRenderTargetStorage);
477 if (error.isError())
478 {
479 SafeDelete(newRenderTargetStorage);
480 return error;
481 }
Jamie Madill135570a2014-09-30 16:33:51 -0400482 }
483 }
484
Geoff Langef7b0162014-09-04 13:29:23 -0400485 return gl::Error(GL_NO_ERROR);
Jamie Madill135570a2014-09-30 16:33:51 -0400486}
487
Jamie Madille76bdda2014-10-20 17:13:52 -0400488bool TextureD3D::canCreateRenderTargetForImage(const gl::ImageIndex &index) const
489{
Jamie Madill30d6c252014-11-13 10:03:33 -0500490 Image *image = getImage(index);
Jamie Madille76bdda2014-10-20 17:13:52 -0400491 bool levelsComplete = (isImageComplete(index) && isImageComplete(getImageIndex(0, 0)));
492 return (image->isRenderableFormat() && levelsComplete);
493}
494
Jamie Madill710e5772014-10-20 17:13:53 -0400495gl::Error TextureD3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
496{
497 if (mTexStorage)
498 {
499 ASSERT(isValidIndex(index));
500 Image *image = getImage(index);
501 ImageD3D *imageD3D = ImageD3D::makeImageD3D(image);
502 gl::Error error = imageD3D->copyToStorage(mTexStorage, index, region);
503 if (error.isError())
504 {
505 return error;
506 }
507
508 image->markClean();
509 }
510
511 return gl::Error(GL_NO_ERROR);
512}
513
Jamie Madill93e13fb2014-11-06 15:27:25 -0500514TextureD3D_2D::TextureD3D_2D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -0400515 : TextureD3D(renderer)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700516{
517 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
518 {
519 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
520 }
521}
522
523TextureD3D_2D::~TextureD3D_2D()
524{
Austin Kinross69822602014-08-12 15:51:37 -0700525 // Delete the Images before the TextureStorage.
526 // Images might be relying on the TextureStorage for some of their data.
527 // 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 -0700528 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
529 {
530 delete mImageArray[i];
531 }
Austin Kinross69822602014-08-12 15:51:37 -0700532
533 SafeDelete(mTexStorage);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700534}
535
Brandon Jonescef06ff2014-08-05 13:27:48 -0700536Image *TextureD3D_2D::getImage(int level, int layer) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700537{
538 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -0700539 ASSERT(layer == 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700540 return mImageArray[level];
541}
542
Jamie Madillfeda4d22014-09-17 13:03:29 -0400543Image *TextureD3D_2D::getImage(const gl::ImageIndex &index) const
544{
545 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -0400546 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -0400547 ASSERT(index.type == GL_TEXTURE_2D);
548 return mImageArray[index.mipIndex];
549}
550
Brandon Jonescef06ff2014-08-05 13:27:48 -0700551GLsizei TextureD3D_2D::getLayerCount(int level) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700552{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700553 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
554 return 1;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700555}
556
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700557GLsizei TextureD3D_2D::getWidth(GLint level) const
558{
559 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
560 return mImageArray[level]->getWidth();
561 else
562 return 0;
563}
564
565GLsizei TextureD3D_2D::getHeight(GLint level) const
566{
567 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
568 return mImageArray[level]->getHeight();
569 else
570 return 0;
571}
572
573GLenum TextureD3D_2D::getInternalFormat(GLint level) const
574{
575 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
576 return mImageArray[level]->getInternalFormat();
577 else
578 return GL_NONE;
579}
580
581GLenum TextureD3D_2D::getActualFormat(GLint level) const
582{
583 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
584 return mImageArray[level]->getActualFormat();
585 else
586 return GL_NONE;
587}
588
589bool TextureD3D_2D::isDepth(GLint level) const
590{
Geoff Lang5d601382014-07-22 15:14:06 -0400591 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700592}
593
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400594gl::Error TextureD3D_2D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
595 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
596 const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700597{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700598 ASSERT(target == GL_TEXTURE_2D && depth == 1);
599
Geoff Lang5d601382014-07-22 15:14:06 -0400600 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
601
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700602 bool fastUnpacked = false;
603
Brandon Jonescef06ff2014-08-05 13:27:48 -0700604 redefineImage(level, sizedInternalFormat, width, height);
605
Jamie Madillba6bc952014-10-06 10:56:22 -0400606 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
607
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700608 // Attempt a fast gpu copy of the pixel data to the surface
609 if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
610 {
611 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -0400612 RenderTarget *destRenderTarget = NULL;
613 gl::Error error = getRenderTarget(index, &destRenderTarget);
614 if (error.isError())
615 {
616 return error;
617 }
618
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700619 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
620
Geoff Lang64f23f62014-09-10 14:40:12 -0400621 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
622 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700623 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400624 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700625 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400626
627 // Ensure we don't overwrite our newly initialized data
628 mImageArray[level]->markClean();
629
630 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700631 }
632
633 if (!fastUnpacked)
634 {
Jamie Madillba6bc952014-10-06 10:56:22 -0400635 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400636 if (error.isError())
637 {
638 return error;
639 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700640 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400641
642 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700643}
644
Geoff Langb5348332014-09-02 13:16:34 -0400645gl::Error TextureD3D_2D::setCompressedImage(GLenum target, GLint level, GLenum format,
646 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400647 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700648{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700649 ASSERT(target == GL_TEXTURE_2D && depth == 1);
650
651 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
652 redefineImage(level, format, width, height);
653
Jamie Madillc751d1e2014-10-21 17:46:29 -0400654 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700655}
656
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400657gl::Error TextureD3D_2D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
658 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
659 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700660{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700661 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
662
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700663 bool fastUnpacked = false;
664
Jamie Madillac7579c2014-09-17 16:59:33 -0400665 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400666 gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700667 if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
668 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400669 RenderTarget *renderTarget = NULL;
670 gl::Error error = getRenderTarget(index, &renderTarget);
671 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700672 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400673 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700674 }
Geoff Lang64f23f62014-09-10 14:40:12 -0400675
676 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
677 if (error.isError())
678 {
679 return error;
680 }
681
682 // Ensure we don't overwrite our newly initialized data
683 mImageArray[level]->markClean();
684
685 fastUnpacked = true;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700686 }
687
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400688 if (!fastUnpacked)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700689 {
Jamie Madille6b6da02014-10-02 11:03:14 -0400690 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
691 unpack, pixels, index);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700692 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -0400693
694 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700695}
696
Geoff Langb5348332014-09-02 13:16:34 -0400697gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
698 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -0400699 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700700{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700701 ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
702
Jamie Madillc751d1e2014-10-21 17:46:29 -0400703 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -0400704 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700705 {
Geoff Langb5348332014-09-02 13:16:34 -0400706 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700707 }
Geoff Langb5348332014-09-02 13:16:34 -0400708
Jamie Madill7cb2b9d2014-10-02 11:03:13 -0400709 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
710 gl::Box region(xoffset, yoffset, 0, width, height, 1);
711 return commitRegion(index, region);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700712}
713
Geoff Langef7b0162014-09-04 13:29:23 -0400714gl::Error TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height,
715 gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700716{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700717 ASSERT(target == GL_TEXTURE_2D);
718
719 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
720 redefineImage(level, sizedInternalFormat, width, height);
721
Jamie Madill82bf0c52014-10-03 11:50:53 -0400722 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400723 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400724
Jamie Madille76bdda2014-10-20 17:13:52 -0400725 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700726 {
Geoff Langef7b0162014-09-04 13:29:23 -0400727 gl::Error error = mImageArray[level]->copy(0, 0, 0, sourceRect, source);
728 if (error.isError())
729 {
730 return error;
731 }
732
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700733 mDirtyImages = true;
734 }
735 else
736 {
Geoff Langef7b0162014-09-04 13:29:23 -0400737 gl::Error error = ensureRenderTarget();
738 if (error.isError())
739 {
740 return error;
741 }
742
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700743 mImageArray[level]->markClean();
744
745 if (width != 0 && height != 0 && isValidLevel(level))
746 {
Geoff Langef7b0162014-09-04 13:29:23 -0400747 gl::Error error = mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
748 if (error.isError())
749 {
750 return error;
751 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700752 }
753 }
Geoff Langef7b0162014-09-04 13:29:23 -0400754
755 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700756}
757
Geoff Langef7b0162014-09-04 13:29:23 -0400758gl::Error TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
759 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700760{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700761 ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
762
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700763 // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
764 // the current level we're copying to is defined (with appropriate format, width & height)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700765
Jamie Madill82bf0c52014-10-03 11:50:53 -0400766 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -0400767 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -0400768
Jamie Madille76bdda2014-10-20 17:13:52 -0400769 if (!canCreateRenderTargetForImage(index))
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700770 {
Geoff Langef7b0162014-09-04 13:29:23 -0400771 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
772 if (error.isError())
773 {
774 return error;
775 }
776
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700777 mDirtyImages = true;
778 }
779 else
780 {
Geoff Langef7b0162014-09-04 13:29:23 -0400781 gl::Error error = ensureRenderTarget();
782 if (error.isError())
783 {
784 return error;
785 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700786
787 if (isValidLevel(level))
788 {
Geoff Langef7b0162014-09-04 13:29:23 -0400789 error = updateStorageLevel(level);
790 if (error.isError())
791 {
792 return error;
793 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700794
Geoff Langef7b0162014-09-04 13:29:23 -0400795 error = mRenderer->copyImage2D(source, sourceRect,
796 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
797 xoffset, yoffset, mTexStorage, level);
798 if (error.isError())
799 {
800 return error;
801 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700802 }
803 }
Geoff Langef7b0162014-09-04 13:29:23 -0400804
805 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700806}
807
Geoff Lang1f8532b2014-09-05 09:46:13 -0400808gl::Error TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700809{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700810 ASSERT(target == GL_TEXTURE_2D && depth == 1);
811
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700812 for (int level = 0; level < levels; level++)
813 {
814 GLsizei levelWidth = std::max(1, width >> level);
815 GLsizei levelHeight = std::max(1, height >> level);
816 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, levelWidth, levelHeight, 1, true);
817 }
818
819 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
820 {
821 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
822 }
823
Geoff Lang1f8532b2014-09-05 09:46:13 -0400824 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -0400825 bool renderTarget = IsRenderTargetUsage(mUsage);
826 TextureStorage *storage = mRenderer->createTextureStorage2D(internalformat, renderTarget, width, height, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -0400827
828 gl::Error error = setCompleteTexStorage(storage);
829 if (error.isError())
830 {
831 SafeDelete(storage);
832 return error;
833 }
834
835 mImmutable = true;
836
837 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700838}
839
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700840void TextureD3D_2D::bindTexImage(egl::Surface *surface)
841{
842 GLenum internalformat = surface->getFormat();
843
844 mImageArray[0]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, surface->getWidth(), surface->getHeight(), 1, true);
845
846 if (mTexStorage)
847 {
848 SafeDelete(mTexStorage);
849 }
Jamie Madill2f06dbf2014-09-18 15:08:50 -0400850
851 mTexStorage = mRenderer->createTextureStorage2D(surface->getSwapChain());
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700852
853 mDirtyImages = true;
854}
855
856void TextureD3D_2D::releaseTexImage()
857{
858 if (mTexStorage)
859 {
860 SafeDelete(mTexStorage);
861 }
862
863 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
864 {
865 mImageArray[i]->redefine(mRenderer, GL_TEXTURE_2D, GL_NONE, 0, 0, 0, true);
866 }
867}
868
Jamie Madill4aa79e12014-09-29 10:46:14 -0400869void TextureD3D_2D::initMipmapsImages()
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700870{
Brandon Jonescef06ff2014-08-05 13:27:48 -0700871 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700872 int levelCount = mipLevels();
Brandon Jonescef06ff2014-08-05 13:27:48 -0700873 for (int level = 1; level < levelCount; level++)
874 {
875 redefineImage(level, getBaseLevelInternalFormat(),
876 std::max(getBaseLevelWidth() >> level, 1),
877 std::max(getBaseLevelHeight() >> level, 1));
878 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700879}
880
Jamie Madillac7579c2014-09-17 16:59:33 -0400881unsigned int TextureD3D_2D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700882{
Jamie Madillac7579c2014-09-17 16:59:33 -0400883 ASSERT(!index.hasLayer());
Geoff Langef7b0162014-09-04 13:29:23 -0400884 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700885}
886
Geoff Lang64f23f62014-09-10 14:40:12 -0400887gl::Error TextureD3D_2D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700888{
Jamie Madillac7579c2014-09-17 16:59:33 -0400889 ASSERT(!index.hasLayer());
Brandon Jonescef06ff2014-08-05 13:27:48 -0700890
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700891 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -0400892 gl::Error error = ensureRenderTarget();
893 if (error.isError())
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700894 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400895 return error;
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700896 }
897
Geoff Langef7b0162014-09-04 13:29:23 -0400898 error = updateStorageLevel(index.mipIndex);
899 if (error.isError())
900 {
Geoff Lang64f23f62014-09-10 14:40:12 -0400901 return error;
Geoff Langef7b0162014-09-04 13:29:23 -0400902 }
903
Geoff Lang64f23f62014-09-10 14:40:12 -0400904 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700905}
906
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700907bool TextureD3D_2D::isValidLevel(int level) const
908{
909 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : false);
910}
911
912bool TextureD3D_2D::isLevelComplete(int level) const
913{
914 if (isImmutable())
915 {
916 return true;
917 }
918
Brandon Jones78b1acd2014-07-15 15:33:07 -0700919 const Image *baseImage = getBaseLevelImage();
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700920
921 GLsizei width = baseImage->getWidth();
922 GLsizei height = baseImage->getHeight();
923
924 if (width <= 0 || height <= 0)
925 {
926 return false;
927 }
928
929 // The base image level is complete if the width and height are positive
930 if (level == 0)
931 {
932 return true;
933 }
934
935 ASSERT(level >= 1 && level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
Brandon Jones78b1acd2014-07-15 15:33:07 -0700936 ImageD3D *image = mImageArray[level];
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700937
938 if (image->getInternalFormat() != baseImage->getInternalFormat())
939 {
940 return false;
941 }
942
943 if (image->getWidth() != std::max(1, width >> level))
944 {
945 return false;
946 }
947
948 if (image->getHeight() != std::max(1, height >> level))
949 {
950 return false;
951 }
952
953 return true;
954}
955
Jamie Madille76bdda2014-10-20 17:13:52 -0400956bool TextureD3D_2D::isImageComplete(const gl::ImageIndex &index) const
957{
958 return isLevelComplete(index.mipIndex);
959}
960
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700961// Constructs a native texture resource from the texture images
Geoff Langef7b0162014-09-04 13:29:23 -0400962gl::Error TextureD3D_2D::initializeStorage(bool renderTarget)
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700963{
964 // Only initialize the first time this texture is used as a render target or shader resource
965 if (mTexStorage)
966 {
Geoff Langef7b0162014-09-04 13:29:23 -0400967 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700968 }
969
970 // do not attempt to create storage for nonexistant data
971 if (!isLevelComplete(0))
972 {
Geoff Langef7b0162014-09-04 13:29:23 -0400973 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700974 }
975
976 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
977
Geoff Langef7b0162014-09-04 13:29:23 -0400978 TextureStorage *storage = NULL;
979 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
980 if (error.isError())
981 {
982 return error;
983 }
984
985 error = setCompleteTexStorage(storage);
986 if (error.isError())
987 {
988 SafeDelete(storage);
989 return error;
990 }
991
Brandon Jonesf47bebc2014-07-09 14:28:42 -0700992 ASSERT(mTexStorage);
993
994 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -0400995 error = updateStorage();
996 if (error.isError())
997 {
998 return error;
999 }
1000
1001 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001002}
1003
Geoff Langef7b0162014-09-04 13:29:23 -04001004gl::Error TextureD3D_2D::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001005{
1006 GLsizei width = getBaseLevelWidth();
1007 GLsizei height = getBaseLevelHeight();
Jamie Madillc4833262014-09-18 16:18:26 -04001008 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001009
1010 ASSERT(width > 0 && height > 0);
1011
1012 // use existing storage level count, when previously specified by TexStorage*D
1013 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
1014
Geoff Langef7b0162014-09-04 13:29:23 -04001015 // TODO(geofflang): Determine if the texture creation succeeded
1016 *outTexStorage = mRenderer->createTextureStorage2D(internalFormat, renderTarget, width, height, levels);
1017
1018 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001019}
1020
Geoff Langef7b0162014-09-04 13:29:23 -04001021gl::Error TextureD3D_2D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001022{
Geoff Langef7b0162014-09-04 13:29:23 -04001023 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001024 {
Geoff Langef7b0162014-09-04 13:29:23 -04001025 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001026 {
Geoff Langef7b0162014-09-04 13:29:23 -04001027 gl::Error error = mImageArray[level]->setManagedSurface2D(newCompleteTexStorage, level);
1028 if (error.isError())
1029 {
1030 return error;
1031 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001032 }
1033 }
1034
Geoff Langef7b0162014-09-04 13:29:23 -04001035 SafeDelete(mTexStorage);
1036 mTexStorage = newCompleteTexStorage;
1037
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001038 mDirtyImages = true;
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::updateStorage()
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001044{
1045 ASSERT(mTexStorage != NULL);
1046 GLint storageLevels = mTexStorage->getLevelCount();
1047 for (int level = 0; level < storageLevels; level++)
1048 {
1049 if (mImageArray[level]->isDirty() && isLevelComplete(level))
1050 {
Geoff Langef7b0162014-09-04 13:29:23 -04001051 gl::Error error = updateStorageLevel(level);
1052 if (error.isError())
1053 {
1054 return error;
1055 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001056 }
1057 }
Geoff Langef7b0162014-09-04 13:29:23 -04001058
1059 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001060}
1061
Geoff Langef7b0162014-09-04 13:29:23 -04001062gl::Error TextureD3D_2D::updateStorageLevel(int level)
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001063{
1064 ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
1065 ASSERT(isLevelComplete(level));
1066
1067 if (mImageArray[level]->isDirty())
1068 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001069 gl::ImageIndex index = gl::ImageIndex::Make2D(level);
1070 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001071 gl::Error error = commitRegion(index, region);
1072 if (error.isError())
1073 {
1074 return error;
1075 }
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001076 }
Geoff Langef7b0162014-09-04 13:29:23 -04001077
1078 return gl::Error(GL_NO_ERROR);
Brandon Jonesf47bebc2014-07-09 14:28:42 -07001079}
1080
1081void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1082{
1083 // If there currently is a corresponding storage texture image, it has these parameters
1084 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1085 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1086 const GLenum storageFormat = getBaseLevelInternalFormat();
1087
1088 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_2D, internalformat, width, height, 1, false);
1089
1090 if (mTexStorage)
1091 {
1092 const int storageLevels = mTexStorage->getLevelCount();
1093
1094 if ((level >= storageLevels && storageLevels != 0) ||
1095 width != storageWidth ||
1096 height != storageHeight ||
1097 internalformat != storageFormat) // Discard mismatched storage
1098 {
1099 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
1100 {
1101 mImageArray[i]->markDirty();
1102 }
1103
1104 SafeDelete(mTexStorage);
1105 mDirtyImages = true;
1106 }
1107 }
1108}
1109
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001110gl::ImageIndexIterator TextureD3D_2D::imageIterator() const
1111{
1112 return gl::ImageIndexIterator::Make2D(0, mTexStorage->getLevelCount());
1113}
Brandon Jones0511e802014-07-14 16:27:26 -07001114
Jamie Madillcb83dc12014-09-29 10:46:12 -04001115gl::ImageIndex TextureD3D_2D::getImageIndex(GLint mip, GLint /*layer*/) const
1116{
1117 // "layer" does not apply to 2D Textures.
1118 return gl::ImageIndex::Make2D(mip);
1119}
1120
Jamie Madill710e5772014-10-20 17:13:53 -04001121bool TextureD3D_2D::isValidIndex(const gl::ImageIndex &index) const
1122{
1123 return (mTexStorage && index.type == GL_TEXTURE_2D &&
1124 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1125}
1126
Jamie Madill93e13fb2014-11-06 15:27:25 -05001127TextureD3D_Cube::TextureD3D_Cube(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001128 : TextureD3D(renderer)
Brandon Jones0511e802014-07-14 16:27:26 -07001129{
1130 for (int i = 0; i < 6; i++)
1131 {
1132 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1133 {
1134 mImageArray[i][j] = ImageD3D::makeImageD3D(renderer->createImage());
1135 }
1136 }
1137}
1138
1139TextureD3D_Cube::~TextureD3D_Cube()
1140{
Austin Kinross69822602014-08-12 15:51:37 -07001141 // Delete the Images before the TextureStorage.
1142 // Images might be relying on the TextureStorage for some of their data.
1143 // If TextureStorage is deleted before the Images, then their data will be wastefully copied back from the GPU before we delete the Images.
Brandon Jones0511e802014-07-14 16:27:26 -07001144 for (int i = 0; i < 6; i++)
1145 {
1146 for (int j = 0; j < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++j)
1147 {
1148 SafeDelete(mImageArray[i][j]);
1149 }
1150 }
Austin Kinross69822602014-08-12 15:51:37 -07001151
1152 SafeDelete(mTexStorage);
Brandon Jones0511e802014-07-14 16:27:26 -07001153}
1154
Brandon Jonescef06ff2014-08-05 13:27:48 -07001155Image *TextureD3D_Cube::getImage(int level, int layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001156{
1157 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001158 ASSERT(layer < 6);
1159 return mImageArray[layer][level];
Brandon Jones0511e802014-07-14 16:27:26 -07001160}
1161
Jamie Madillfeda4d22014-09-17 13:03:29 -04001162Image *TextureD3D_Cube::getImage(const gl::ImageIndex &index) const
1163{
1164 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1165 ASSERT(index.layerIndex < 6);
1166 return mImageArray[index.layerIndex][index.mipIndex];
1167}
1168
Brandon Jonescef06ff2014-08-05 13:27:48 -07001169GLsizei TextureD3D_Cube::getLayerCount(int level) const
Brandon Jones0511e802014-07-14 16:27:26 -07001170{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001171 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1172 return 6;
Brandon Jones0511e802014-07-14 16:27:26 -07001173}
1174
Brandon Jonescef06ff2014-08-05 13:27:48 -07001175GLenum TextureD3D_Cube::getInternalFormat(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001176{
1177 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001178 return mImageArray[layer][level]->getInternalFormat();
Brandon Jones0511e802014-07-14 16:27:26 -07001179 else
1180 return GL_NONE;
1181}
1182
Brandon Jonescef06ff2014-08-05 13:27:48 -07001183bool TextureD3D_Cube::isDepth(GLint level, GLint layer) const
Brandon Jones0511e802014-07-14 16:27:26 -07001184{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001185 return gl::GetInternalFormatInfo(getInternalFormat(level, layer)).depthBits > 0;
Brandon Jones0511e802014-07-14 16:27:26 -07001186}
1187
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001188gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1189 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1190 const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001191{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001192 ASSERT(depth == 1);
1193
Geoff Lang5d601382014-07-22 15:14:06 -04001194 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
Jamie Madillba6bc952014-10-06 10:56:22 -04001195 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jones0511e802014-07-14 16:27:26 -07001196
Jamie Madillba6bc952014-10-06 10:56:22 -04001197 redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
Brandon Jones0511e802014-07-14 16:27:26 -07001198
Jamie Madillba6bc952014-10-06 10:56:22 -04001199 return TextureD3D::setImage(unpack, type, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001200}
1201
Geoff Langb5348332014-09-02 13:16:34 -04001202gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
1203 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001204 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001205{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001206 ASSERT(depth == 1);
1207
Brandon Jones0511e802014-07-14 16:27:26 -07001208 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
Brandon Jonescef06ff2014-08-05 13:27:48 -07001209 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
1210
Brandon Jones0511e802014-07-14 16:27:26 -07001211 redefineImage(faceIndex, level, format, width, height);
1212
Jamie Madillc751d1e2014-10-21 17:46:29 -04001213 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[faceIndex][level]);
Brandon Jones0511e802014-07-14 16:27:26 -07001214}
1215
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001216gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1217 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1218 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001219{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001220 ASSERT(depth == 1 && zoffset == 0);
Jamie Madillfeda4d22014-09-17 13:03:29 -04001221 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madille6b6da02014-10-02 11:03:14 -04001222 return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
Brandon Jones0511e802014-07-14 16:27:26 -07001223}
1224
Geoff Langb5348332014-09-02 13:16:34 -04001225gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1226 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001227 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones0511e802014-07-14 16:27:26 -07001228{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001229 ASSERT(depth == 1 && zoffset == 0);
1230
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001231 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001232
Jamie Madillc751d1e2014-10-21 17:46:29 -04001233 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 -04001234 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001235 {
Geoff Langb5348332014-09-02 13:16:34 -04001236 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001237 }
Geoff Langb5348332014-09-02 13:16:34 -04001238
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001239 gl::Box region(xoffset, yoffset, 0, width, height, 1);
1240 return commitRegion(index, region);
Brandon Jones0511e802014-07-14 16:27:26 -07001241}
1242
Geoff Langef7b0162014-09-04 13:29:23 -04001243gl::Error TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1244 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001245{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001246 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Geoff Lang5d601382014-07-22 15:14:06 -04001247 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
1248
Brandon Jones0511e802014-07-14 16:27:26 -07001249 redefineImage(faceIndex, level, sizedInternalFormat, width, height);
1250
Jamie Madill82bf0c52014-10-03 11:50:53 -04001251 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001252 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001253
Jamie Madille76bdda2014-10-20 17:13:52 -04001254 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001255 {
Geoff Langef7b0162014-09-04 13:29:23 -04001256 gl::Error error = mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1257 if (error.isError())
1258 {
1259 return error;
1260 }
1261
Brandon Jones0511e802014-07-14 16:27:26 -07001262 mDirtyImages = true;
1263 }
1264 else
1265 {
Geoff Langef7b0162014-09-04 13:29:23 -04001266 gl::Error error = ensureRenderTarget();
1267 if (error.isError())
1268 {
1269 return error;
1270 }
1271
Brandon Jones0511e802014-07-14 16:27:26 -07001272 mImageArray[faceIndex][level]->markClean();
1273
1274 ASSERT(width == height);
1275
1276 if (width > 0 && isValidFaceLevel(faceIndex, level))
1277 {
Geoff Langef7b0162014-09-04 13:29:23 -04001278 error = mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
1279 if (error.isError())
1280 {
1281 return error;
1282 }
Brandon Jones0511e802014-07-14 16:27:26 -07001283 }
1284 }
Geoff Langef7b0162014-09-04 13:29:23 -04001285
1286 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001287}
1288
Geoff Langef7b0162014-09-04 13:29:23 -04001289gl::Error TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1290 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones0511e802014-07-14 16:27:26 -07001291{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001292 int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
Brandon Jones0511e802014-07-14 16:27:26 -07001293
Jamie Madill82bf0c52014-10-03 11:50:53 -04001294 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001295 gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001296
Jamie Madille76bdda2014-10-20 17:13:52 -04001297 if (!canCreateRenderTargetForImage(index))
Brandon Jones0511e802014-07-14 16:27:26 -07001298 {
Geoff Langef7b0162014-09-04 13:29:23 -04001299 gl::Error error =mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
1300 if (error.isError())
1301 {
1302 return error;
1303 }
1304
Brandon Jones0511e802014-07-14 16:27:26 -07001305 mDirtyImages = true;
1306 }
1307 else
1308 {
Geoff Langef7b0162014-09-04 13:29:23 -04001309 gl::Error error = ensureRenderTarget();
1310 if (error.isError())
1311 {
1312 return error;
1313 }
Brandon Jones0511e802014-07-14 16:27:26 -07001314
1315 if (isValidFaceLevel(faceIndex, level))
1316 {
Geoff Langef7b0162014-09-04 13:29:23 -04001317 error = updateStorageFaceLevel(faceIndex, level);
1318 if (error.isError())
1319 {
1320 return error;
1321 }
Brandon Jones0511e802014-07-14 16:27:26 -07001322
Geoff Langef7b0162014-09-04 13:29:23 -04001323 error = mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1324 xoffset, yoffset, mTexStorage, target, level);
1325 if (error.isError())
1326 {
1327 return error;
1328 }
Brandon Jones0511e802014-07-14 16:27:26 -07001329 }
1330 }
Geoff Langef7b0162014-09-04 13:29:23 -04001331
1332 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001333}
1334
Geoff Lang1f8532b2014-09-05 09:46:13 -04001335gl::Error TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones0511e802014-07-14 16:27:26 -07001336{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001337 ASSERT(width == height);
1338 ASSERT(depth == 1);
1339
Brandon Jones0511e802014-07-14 16:27:26 -07001340 for (int level = 0; level < levels; level++)
1341 {
Brandon Jonescef06ff2014-08-05 13:27:48 -07001342 GLsizei mipSize = std::max(1, width >> level);
Brandon Jones0511e802014-07-14 16:27:26 -07001343 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1344 {
1345 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, mipSize, mipSize, 1, true);
1346 }
1347 }
1348
1349 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1350 {
1351 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1352 {
1353 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, GL_NONE, 0, 0, 0, true);
1354 }
1355 }
1356
Geoff Lang1f8532b2014-09-05 09:46:13 -04001357 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001358 bool renderTarget = IsRenderTargetUsage(mUsage);
Jamie Madill2f06dbf2014-09-18 15:08:50 -04001359 TextureStorage *storage = mRenderer->createTextureStorageCube(internalformat, renderTarget, width, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001360
1361 gl::Error error = setCompleteTexStorage(storage);
1362 if (error.isError())
1363 {
1364 SafeDelete(storage);
1365 return error;
1366 }
1367
1368 mImmutable = true;
1369
1370 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001371}
1372
Brandon Jones0511e802014-07-14 16:27:26 -07001373// Tests for cube texture completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81.
1374bool TextureD3D_Cube::isCubeComplete() const
1375{
1376 int baseWidth = getBaseLevelWidth();
1377 int baseHeight = getBaseLevelHeight();
1378 GLenum baseFormat = getBaseLevelInternalFormat();
1379
1380 if (baseWidth <= 0 || baseWidth != baseHeight)
1381 {
1382 return false;
1383 }
1384
1385 for (int faceIndex = 1; faceIndex < 6; faceIndex++)
1386 {
1387 const ImageD3D &faceBaseImage = *mImageArray[faceIndex][0];
1388
1389 if (faceBaseImage.getWidth() != baseWidth ||
1390 faceBaseImage.getHeight() != baseHeight ||
1391 faceBaseImage.getInternalFormat() != baseFormat )
1392 {
1393 return false;
1394 }
1395 }
1396
1397 return true;
1398}
1399
Brandon Jones6053a522014-07-25 16:22:09 -07001400void TextureD3D_Cube::bindTexImage(egl::Surface *surface)
1401{
1402 UNREACHABLE();
1403}
1404
1405void TextureD3D_Cube::releaseTexImage()
1406{
1407 UNREACHABLE();
1408}
1409
1410
Jamie Madill4aa79e12014-09-29 10:46:14 -04001411void TextureD3D_Cube::initMipmapsImages()
Brandon Jones0511e802014-07-14 16:27:26 -07001412{
1413 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1414 int levelCount = mipLevels();
1415 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1416 {
1417 for (int level = 1; level < levelCount; level++)
1418 {
1419 int faceLevelSize = (std::max(mImageArray[faceIndex][0]->getWidth() >> level, 1));
1420 redefineImage(faceIndex, level, mImageArray[faceIndex][0]->getInternalFormat(), faceLevelSize, faceLevelSize);
1421 }
1422 }
Brandon Jones0511e802014-07-14 16:27:26 -07001423}
1424
Jamie Madillac7579c2014-09-17 16:59:33 -04001425unsigned int TextureD3D_Cube::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones0511e802014-07-14 16:27:26 -07001426{
Geoff Langef7b0162014-09-04 13:29:23 -04001427 return (ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones0511e802014-07-14 16:27:26 -07001428}
1429
Geoff Lang64f23f62014-09-10 14:40:12 -04001430gl::Error TextureD3D_Cube::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones0511e802014-07-14 16:27:26 -07001431{
Jamie Madillac7579c2014-09-17 16:59:33 -04001432 ASSERT(gl::IsCubemapTextureTarget(index.type));
Brandon Jones0511e802014-07-14 16:27:26 -07001433
1434 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001435 gl::Error error = ensureRenderTarget();
1436 if (error.isError())
Brandon Jones0511e802014-07-14 16:27:26 -07001437 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001438 return error;
Brandon Jones0511e802014-07-14 16:27:26 -07001439 }
1440
Geoff Langef7b0162014-09-04 13:29:23 -04001441 error = updateStorageFaceLevel(index.layerIndex, index.mipIndex);
1442 if (error.isError())
1443 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001444 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04001445 }
1446
Geoff Lang64f23f62014-09-10 14:40:12 -04001447 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones0511e802014-07-14 16:27:26 -07001448}
1449
Geoff Langef7b0162014-09-04 13:29:23 -04001450gl::Error TextureD3D_Cube::initializeStorage(bool renderTarget)
Brandon Jones0511e802014-07-14 16:27:26 -07001451{
1452 // Only initialize the first time this texture is used as a render target or shader resource
1453 if (mTexStorage)
1454 {
Geoff Langef7b0162014-09-04 13:29:23 -04001455 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001456 }
1457
1458 // do not attempt to create storage for nonexistant data
1459 if (!isFaceLevelComplete(0, 0))
1460 {
Geoff Langef7b0162014-09-04 13:29:23 -04001461 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001462 }
1463
1464 bool createRenderTarget = (renderTarget || IsRenderTargetUsage(mUsage));
1465
Geoff Langef7b0162014-09-04 13:29:23 -04001466 TextureStorage *storage = NULL;
1467 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
1468 if (error.isError())
1469 {
1470 return error;
1471 }
1472
1473 error = setCompleteTexStorage(storage);
1474 if (error.isError())
1475 {
1476 SafeDelete(storage);
1477 return error;
1478 }
1479
Brandon Jones0511e802014-07-14 16:27:26 -07001480 ASSERT(mTexStorage);
1481
1482 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04001483 error = updateStorage();
1484 if (error.isError())
1485 {
1486 return error;
1487 }
1488
1489 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001490}
1491
Geoff Langef7b0162014-09-04 13:29:23 -04001492gl::Error TextureD3D_Cube::createCompleteStorage(bool renderTarget, TextureStorage **outTexStorage) const
Brandon Jones0511e802014-07-14 16:27:26 -07001493{
1494 GLsizei size = getBaseLevelWidth();
1495
1496 ASSERT(size > 0);
1497
1498 // use existing storage level count, when previously specified by TexStorage*D
1499 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(size, size, 1));
1500
Geoff Langef7b0162014-09-04 13:29:23 -04001501 // TODO (geofflang): detect if storage creation succeeded
1502 *outTexStorage = mRenderer->createTextureStorageCube(getBaseLevelInternalFormat(), renderTarget, size, levels);
1503
1504 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001505}
1506
Geoff Langef7b0162014-09-04 13:29:23 -04001507gl::Error TextureD3D_Cube::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones0511e802014-07-14 16:27:26 -07001508{
Geoff Langef7b0162014-09-04 13:29:23 -04001509 if (newCompleteTexStorage && newCompleteTexStorage->isManaged())
Brandon Jones0511e802014-07-14 16:27:26 -07001510 {
1511 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1512 {
Geoff Langef7b0162014-09-04 13:29:23 -04001513 for (int level = 0; level < newCompleteTexStorage->getLevelCount(); level++)
Brandon Jones0511e802014-07-14 16:27:26 -07001514 {
Geoff Langef7b0162014-09-04 13:29:23 -04001515 gl::Error error = mImageArray[faceIndex][level]->setManagedSurfaceCube(newCompleteTexStorage, faceIndex, level);
1516 if (error.isError())
1517 {
1518 return error;
1519 }
Brandon Jones0511e802014-07-14 16:27:26 -07001520 }
1521 }
1522 }
1523
Geoff Langef7b0162014-09-04 13:29:23 -04001524 SafeDelete(mTexStorage);
1525 mTexStorage = newCompleteTexStorage;
1526
Brandon Jones0511e802014-07-14 16:27:26 -07001527 mDirtyImages = true;
Geoff Langef7b0162014-09-04 13:29:23 -04001528 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001529}
1530
Geoff Langef7b0162014-09-04 13:29:23 -04001531gl::Error TextureD3D_Cube::updateStorage()
Brandon Jones0511e802014-07-14 16:27:26 -07001532{
1533 ASSERT(mTexStorage != NULL);
1534 GLint storageLevels = mTexStorage->getLevelCount();
1535 for (int face = 0; face < 6; face++)
1536 {
1537 for (int level = 0; level < storageLevels; level++)
1538 {
1539 if (mImageArray[face][level]->isDirty() && isFaceLevelComplete(face, level))
1540 {
Geoff Langef7b0162014-09-04 13:29:23 -04001541 gl::Error error = updateStorageFaceLevel(face, level);
1542 if (error.isError())
1543 {
1544 return error;
1545 }
Brandon Jones0511e802014-07-14 16:27:26 -07001546 }
1547 }
1548 }
Geoff Langef7b0162014-09-04 13:29:23 -04001549
1550 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001551}
1552
Brandon Jones0511e802014-07-14 16:27:26 -07001553bool TextureD3D_Cube::isValidFaceLevel(int faceIndex, int level) const
1554{
1555 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
1556}
1557
Brandon Jones0511e802014-07-14 16:27:26 -07001558bool TextureD3D_Cube::isFaceLevelComplete(int faceIndex, int level) const
1559{
1560 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1561
1562 if (isImmutable())
1563 {
1564 return true;
1565 }
1566
1567 int baseSize = getBaseLevelWidth();
1568
1569 if (baseSize <= 0)
1570 {
1571 return false;
1572 }
1573
1574 // "isCubeComplete" checks for base level completeness and we must call that
1575 // to determine if any face at level 0 is complete. We omit that check here
1576 // to avoid re-checking cube-completeness for every face at level 0.
1577 if (level == 0)
1578 {
1579 return true;
1580 }
1581
1582 // Check that non-zero levels are consistent with the base level.
1583 const ImageD3D *faceLevelImage = mImageArray[faceIndex][level];
1584
1585 if (faceLevelImage->getInternalFormat() != getBaseLevelInternalFormat())
1586 {
1587 return false;
1588 }
1589
1590 if (faceLevelImage->getWidth() != std::max(1, baseSize >> level))
1591 {
1592 return false;
1593 }
1594
1595 return true;
1596}
1597
Jamie Madille76bdda2014-10-20 17:13:52 -04001598bool TextureD3D_Cube::isImageComplete(const gl::ImageIndex &index) const
1599{
1600 return isFaceLevelComplete(index.layerIndex, index.mipIndex);
1601}
1602
Geoff Langef7b0162014-09-04 13:29:23 -04001603gl::Error TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
Brandon Jones0511e802014-07-14 16:27:26 -07001604{
1605 ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
1606 ImageD3D *image = mImageArray[faceIndex][level];
1607
1608 if (image->isDirty())
1609 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001610 GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
1611 gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
1612 gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04001613 gl::Error error = commitRegion(index, region);
1614 if (error.isError())
1615 {
1616 return error;
1617 }
Brandon Jones0511e802014-07-14 16:27:26 -07001618 }
Geoff Langef7b0162014-09-04 13:29:23 -04001619
1620 return gl::Error(GL_NO_ERROR);
Brandon Jones0511e802014-07-14 16:27:26 -07001621}
1622
1623void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
1624{
1625 // If there currently is a corresponding storage texture image, it has these parameters
1626 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
1627 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
1628 const GLenum storageFormat = getBaseLevelInternalFormat();
1629
1630 mImageArray[faceIndex][level]->redefine(mRenderer, GL_TEXTURE_CUBE_MAP, internalformat, width, height, 1, false);
1631
1632 if (mTexStorage)
1633 {
1634 const int storageLevels = mTexStorage->getLevelCount();
1635
1636 if ((level >= storageLevels && storageLevels != 0) ||
1637 width != storageWidth ||
1638 height != storageHeight ||
1639 internalformat != storageFormat) // Discard mismatched storage
1640 {
1641 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1642 {
1643 for (int faceIndex = 0; faceIndex < 6; faceIndex++)
1644 {
1645 mImageArray[faceIndex][level]->markDirty();
1646 }
1647 }
1648
1649 SafeDelete(mTexStorage);
1650
1651 mDirtyImages = true;
1652 }
1653 }
1654}
1655
Jamie Madillef4ac5b2014-09-29 10:46:11 -04001656gl::ImageIndexIterator TextureD3D_Cube::imageIterator() const
1657{
1658 return gl::ImageIndexIterator::MakeCube(0, mTexStorage->getLevelCount());
1659}
Brandon Jones78b1acd2014-07-15 15:33:07 -07001660
Jamie Madillcb83dc12014-09-29 10:46:12 -04001661gl::ImageIndex TextureD3D_Cube::getImageIndex(GLint mip, GLint layer) const
1662{
1663 // The "layer" of the image index corresponds to the cube face
1664 return gl::ImageIndex::MakeCube(gl::TextureCubeMap::layerIndexToTarget(layer), mip);
1665}
1666
Jamie Madill710e5772014-10-20 17:13:53 -04001667bool TextureD3D_Cube::isValidIndex(const gl::ImageIndex &index) const
1668{
1669 return (mTexStorage && gl::IsCubemapTextureTarget(index.type) &&
1670 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
1671}
1672
Jamie Madill93e13fb2014-11-06 15:27:25 -05001673TextureD3D_3D::TextureD3D_3D(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04001674 : TextureD3D(renderer)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001675{
1676 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1677 {
1678 mImageArray[i] = ImageD3D::makeImageD3D(renderer->createImage());
1679 }
1680}
1681
1682TextureD3D_3D::~TextureD3D_3D()
1683{
Austin Kinross69822602014-08-12 15:51:37 -07001684 // Delete the Images before the TextureStorage.
1685 // Images might be relying on the TextureStorage for some of their data.
1686 // 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 -07001687 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++i)
1688 {
1689 delete mImageArray[i];
1690 }
Austin Kinross69822602014-08-12 15:51:37 -07001691
1692 SafeDelete(mTexStorage);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001693}
1694
Brandon Jonescef06ff2014-08-05 13:27:48 -07001695Image *TextureD3D_3D::getImage(int level, int layer) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001696{
1697 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Brandon Jonescef06ff2014-08-05 13:27:48 -07001698 ASSERT(layer == 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001699 return mImageArray[level];
1700}
1701
Jamie Madillfeda4d22014-09-17 13:03:29 -04001702Image *TextureD3D_3D::getImage(const gl::ImageIndex &index) const
1703{
1704 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
Jamie Madillac7579c2014-09-17 16:59:33 -04001705 ASSERT(!index.hasLayer());
Jamie Madillfeda4d22014-09-17 13:03:29 -04001706 ASSERT(index.type == GL_TEXTURE_3D);
1707 return mImageArray[index.mipIndex];
1708}
1709
Brandon Jonescef06ff2014-08-05 13:27:48 -07001710GLsizei TextureD3D_3D::getLayerCount(int level) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07001711{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001712 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
1713 return 1;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001714}
1715
Brandon Jones78b1acd2014-07-15 15:33:07 -07001716GLsizei TextureD3D_3D::getWidth(GLint level) const
1717{
1718 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1719 return mImageArray[level]->getWidth();
1720 else
1721 return 0;
1722}
1723
1724GLsizei TextureD3D_3D::getHeight(GLint level) const
1725{
1726 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1727 return mImageArray[level]->getHeight();
1728 else
1729 return 0;
1730}
1731
1732GLsizei TextureD3D_3D::getDepth(GLint level) const
1733{
1734 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1735 return mImageArray[level]->getDepth();
1736 else
1737 return 0;
1738}
1739
1740GLenum TextureD3D_3D::getInternalFormat(GLint level) const
1741{
1742 if (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1743 return mImageArray[level]->getInternalFormat();
1744 else
1745 return GL_NONE;
1746}
1747
1748bool TextureD3D_3D::isDepth(GLint level) const
1749{
Geoff Lang5d601382014-07-22 15:14:06 -04001750 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001751}
1752
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001753gl::Error TextureD3D_3D::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
1754 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
1755 const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001756{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001757 ASSERT(target == GL_TEXTURE_3D);
Geoff Lang5d601382014-07-22 15:14:06 -04001758 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
1759
Brandon Jones78b1acd2014-07-15 15:33:07 -07001760 redefineImage(level, sizedInternalFormat, width, height, depth);
1761
1762 bool fastUnpacked = false;
1763
Jamie Madillba6bc952014-10-06 10:56:22 -04001764 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1765
Brandon Jones78b1acd2014-07-15 15:33:07 -07001766 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1767 if (isFastUnpackable(unpack, sizedInternalFormat))
1768 {
1769 // Will try to create RT storage if it does not exist
Geoff Lang64f23f62014-09-10 14:40:12 -04001770 RenderTarget *destRenderTarget = NULL;
1771 gl::Error error = getRenderTarget(index, &destRenderTarget);
1772 if (error.isError())
1773 {
1774 return error;
1775 }
1776
Brandon Jones78b1acd2014-07-15 15:33:07 -07001777 gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
1778
Geoff Lang64f23f62014-09-10 14:40:12 -04001779 error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
1780 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001781 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001782 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001783 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001784
1785 // Ensure we don't overwrite our newly initialized data
1786 mImageArray[level]->markClean();
1787
1788 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001789 }
1790
1791 if (!fastUnpacked)
1792 {
Jamie Madillba6bc952014-10-06 10:56:22 -04001793 gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001794 if (error.isError())
1795 {
1796 return error;
1797 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001798 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001799
1800 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001801}
1802
Geoff Langb5348332014-09-02 13:16:34 -04001803gl::Error TextureD3D_3D::setCompressedImage(GLenum target, GLint level, GLenum format,
1804 GLsizei width, GLsizei height,GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001805 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001806{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001807 ASSERT(target == GL_TEXTURE_3D);
1808
Brandon Jones78b1acd2014-07-15 15:33:07 -07001809 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
1810 redefineImage(level, format, width, height, depth);
1811
Jamie Madillc751d1e2014-10-21 17:46:29 -04001812 return TextureD3D::setCompressedImage(unpack, imageSize, pixels, mImageArray[level]);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001813}
1814
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001815gl::Error TextureD3D_3D::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1816 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
1817 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001818{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001819 ASSERT(target == GL_TEXTURE_3D);
1820
Brandon Jones78b1acd2014-07-15 15:33:07 -07001821 bool fastUnpacked = false;
1822
Jamie Madillac7579c2014-09-17 16:59:33 -04001823 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1824
Brandon Jones78b1acd2014-07-15 15:33:07 -07001825 // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
1826 if (isFastUnpackable(unpack, getInternalFormat(level)))
1827 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001828 RenderTarget *destRenderTarget = NULL;
1829 gl::Error error = getRenderTarget(index, &destRenderTarget);
1830 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001831 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001832 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001833 }
Geoff Lang64f23f62014-09-10 14:40:12 -04001834
1835 gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
1836 error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
1837 if (error.isError())
1838 {
1839 return error;
1840 }
1841
1842 // Ensure we don't overwrite our newly initialized data
1843 mImageArray[level]->markClean();
1844
1845 fastUnpacked = true;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001846 }
1847
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001848 if (!fastUnpacked)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001849 {
Jamie Madille6b6da02014-10-02 11:03:14 -04001850 return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
1851 unpack, pixels, index);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001852 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04001853
1854 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001855}
1856
Geoff Langb5348332014-09-02 13:16:34 -04001857gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1858 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001859 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001860{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001861 ASSERT(target == GL_TEXTURE_3D);
1862
Geoff Langb5348332014-09-02 13:16:34 -04001863 gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04001864 format, imageSize, unpack, pixels, mImageArray[level]);
Geoff Langb5348332014-09-02 13:16:34 -04001865 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001866 {
Geoff Langb5348332014-09-02 13:16:34 -04001867 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001868 }
Geoff Langb5348332014-09-02 13:16:34 -04001869
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04001870 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
1871 gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
1872 return commitRegion(index, region);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001873}
1874
Geoff Langef7b0162014-09-04 13:29:23 -04001875gl::Error TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y,
1876 GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jonescef06ff2014-08-05 13:27:48 -07001877{
1878 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04001879 return gl::Error(GL_INVALID_OPERATION, "Copying 3D textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07001880}
1881
Geoff Langef7b0162014-09-04 13:29:23 -04001882gl::Error TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
1883 GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001884{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001885 ASSERT(target == GL_TEXTURE_3D);
1886
Jamie Madill82bf0c52014-10-03 11:50:53 -04001887 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04001888 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
Jamie Madill82bf0c52014-10-03 11:50:53 -04001889
Jamie Madille76bdda2014-10-20 17:13:52 -04001890 if (canCreateRenderTargetForImage(index))
Brandon Jones78b1acd2014-07-15 15:33:07 -07001891 {
Geoff Langef7b0162014-09-04 13:29:23 -04001892 gl::Error error = mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
1893 if (error.isError())
1894 {
1895 return error;
1896 }
1897
Brandon Jones78b1acd2014-07-15 15:33:07 -07001898 mDirtyImages = true;
1899 }
1900 else
1901 {
Geoff Langef7b0162014-09-04 13:29:23 -04001902 gl::Error error = ensureRenderTarget();
1903 if (error.isError())
1904 {
1905 return error;
1906 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001907
1908 if (isValidLevel(level))
1909 {
Geoff Langef7b0162014-09-04 13:29:23 -04001910 error = updateStorageLevel(level);
1911 if (error.isError())
1912 {
1913 return error;
1914 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001915
Geoff Langef7b0162014-09-04 13:29:23 -04001916 error = mRenderer->copyImage3D(source, sourceRect,
1917 gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
1918 xoffset, yoffset, zoffset, mTexStorage, level);
1919 if (error.isError())
1920 {
1921 return error;
1922 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001923 }
1924 }
Geoff Langef7b0162014-09-04 13:29:23 -04001925
1926 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001927}
1928
Geoff Lang1f8532b2014-09-05 09:46:13 -04001929gl::Error TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001930{
Brandon Jonescef06ff2014-08-05 13:27:48 -07001931 ASSERT(target == GL_TEXTURE_3D);
1932
Brandon Jones78b1acd2014-07-15 15:33:07 -07001933 for (int level = 0; level < levels; level++)
1934 {
1935 GLsizei levelWidth = std::max(1, width >> level);
1936 GLsizei levelHeight = std::max(1, height >> level);
1937 GLsizei levelDepth = std::max(1, depth >> level);
1938 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, levelWidth, levelHeight, levelDepth, true);
1939 }
1940
1941 for (int level = levels; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
1942 {
1943 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, GL_NONE, 0, 0, 0, true);
1944 }
1945
Geoff Lang1f8532b2014-09-05 09:46:13 -04001946 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04001947 bool renderTarget = IsRenderTargetUsage(mUsage);
1948 TextureStorage *storage = mRenderer->createTextureStorage3D(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04001949
1950 gl::Error error = setCompleteTexStorage(storage);
1951 if (error.isError())
1952 {
1953 SafeDelete(storage);
1954 return error;
1955 }
1956
1957 mImmutable = true;
1958
1959 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001960}
1961
Brandon Jones6053a522014-07-25 16:22:09 -07001962void TextureD3D_3D::bindTexImage(egl::Surface *surface)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001963{
Brandon Jones6053a522014-07-25 16:22:09 -07001964 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001965}
1966
Brandon Jones6053a522014-07-25 16:22:09 -07001967void TextureD3D_3D::releaseTexImage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001968{
Brandon Jones6053a522014-07-25 16:22:09 -07001969 UNREACHABLE();
Brandon Jones78b1acd2014-07-15 15:33:07 -07001970}
1971
Brandon Jones6053a522014-07-25 16:22:09 -07001972
Jamie Madill4aa79e12014-09-29 10:46:14 -04001973void TextureD3D_3D::initMipmapsImages()
Brandon Jones78b1acd2014-07-15 15:33:07 -07001974{
1975 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
1976 int levelCount = mipLevels();
1977 for (int level = 1; level < levelCount; level++)
1978 {
1979 redefineImage(level, getBaseLevelInternalFormat(),
1980 std::max(getBaseLevelWidth() >> level, 1),
1981 std::max(getBaseLevelHeight() >> level, 1),
1982 std::max(getBaseLevelDepth() >> level, 1));
1983 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07001984}
1985
Jamie Madillac7579c2014-09-17 16:59:33 -04001986unsigned int TextureD3D_3D::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001987{
Geoff Langef7b0162014-09-04 13:29:23 -04001988 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones78b1acd2014-07-15 15:33:07 -07001989}
1990
Geoff Lang64f23f62014-09-10 14:40:12 -04001991gl::Error TextureD3D_3D::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones78b1acd2014-07-15 15:33:07 -07001992{
1993 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04001994 gl::Error error = ensureRenderTarget();
1995 if (error.isError())
Brandon Jones78b1acd2014-07-15 15:33:07 -07001996 {
Geoff Lang64f23f62014-09-10 14:40:12 -04001997 return error;
Brandon Jones78b1acd2014-07-15 15:33:07 -07001998 }
1999
Jamie Madillac7579c2014-09-17 16:59:33 -04002000 if (index.hasLayer())
Brandon Jones78b1acd2014-07-15 15:33:07 -07002001 {
Geoff Langef7b0162014-09-04 13:29:23 -04002002 error = updateStorage();
2003 if (error.isError())
2004 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002005 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002006 }
Jamie Madillac7579c2014-09-17 16:59:33 -04002007 }
2008 else
2009 {
Geoff Langef7b0162014-09-04 13:29:23 -04002010 error = updateStorageLevel(index.mipIndex);
2011 if (error.isError())
2012 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002013 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002014 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002015 }
2016
Geoff Lang64f23f62014-09-10 14:40:12 -04002017 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002018}
2019
Geoff Langef7b0162014-09-04 13:29:23 -04002020gl::Error TextureD3D_3D::initializeStorage(bool renderTarget)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002021{
2022 // Only initialize the first time this texture is used as a render target or shader resource
2023 if (mTexStorage)
2024 {
Geoff Langef7b0162014-09-04 13:29:23 -04002025 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002026 }
2027
2028 // do not attempt to create storage for nonexistant data
2029 if (!isLevelComplete(0))
2030 {
Geoff Langef7b0162014-09-04 13:29:23 -04002031 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002032 }
2033
2034 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2035
Jamie Madill30d6c252014-11-13 10:03:33 -05002036 TextureStorage *storage = NULL;
Geoff Langef7b0162014-09-04 13:29:23 -04002037 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2038 if (error.isError())
2039 {
2040 return error;
2041 }
2042
2043 error = setCompleteTexStorage(storage);
2044 if (error.isError())
2045 {
2046 SafeDelete(storage);
2047 return error;
2048 }
2049
Brandon Jones78b1acd2014-07-15 15:33:07 -07002050 ASSERT(mTexStorage);
2051
2052 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002053 error = updateStorage();
2054 if (error.isError())
2055 {
2056 return error;
2057 }
2058
2059 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002060}
2061
Geoff Langef7b0162014-09-04 13:29:23 -04002062gl::Error TextureD3D_3D::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones78b1acd2014-07-15 15:33:07 -07002063{
2064 GLsizei width = getBaseLevelWidth();
2065 GLsizei height = getBaseLevelHeight();
2066 GLsizei depth = getBaseLevelDepth();
Jamie Madillc4833262014-09-18 16:18:26 -04002067 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones78b1acd2014-07-15 15:33:07 -07002068
2069 ASSERT(width > 0 && height > 0 && depth > 0);
2070
2071 // use existing storage level count, when previously specified by TexStorage*D
2072 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, depth));
2073
Geoff Langef7b0162014-09-04 13:29:23 -04002074 // TODO: Verify creation of the storage succeeded
2075 *outStorage = mRenderer->createTextureStorage3D(internalFormat, renderTarget, width, height, depth, levels);
2076
2077 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002078}
2079
Geoff Langef7b0162014-09-04 13:29:23 -04002080gl::Error TextureD3D_3D::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002081{
2082 SafeDelete(mTexStorage);
2083 mTexStorage = newCompleteTexStorage;
2084 mDirtyImages = true;
2085
2086 // We do not support managed 3D storage, as that is D3D9/ES2-only
2087 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002088
2089 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002090}
2091
Geoff Langef7b0162014-09-04 13:29:23 -04002092gl::Error TextureD3D_3D::updateStorage()
Brandon Jones78b1acd2014-07-15 15:33:07 -07002093{
2094 ASSERT(mTexStorage != NULL);
2095 GLint storageLevels = mTexStorage->getLevelCount();
2096 for (int level = 0; level < storageLevels; level++)
2097 {
2098 if (mImageArray[level]->isDirty() && isLevelComplete(level))
2099 {
Geoff Langef7b0162014-09-04 13:29:23 -04002100 gl::Error error = updateStorageLevel(level);
2101 if (error.isError())
2102 {
2103 return error;
2104 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002105 }
2106 }
Geoff Langef7b0162014-09-04 13:29:23 -04002107
2108 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002109}
2110
Brandon Jones78b1acd2014-07-15 15:33:07 -07002111bool TextureD3D_3D::isValidLevel(int level) const
2112{
2113 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2114}
2115
2116bool TextureD3D_3D::isLevelComplete(int level) const
2117{
2118 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2119
2120 if (isImmutable())
2121 {
2122 return true;
2123 }
2124
2125 GLsizei width = getBaseLevelWidth();
2126 GLsizei height = getBaseLevelHeight();
2127 GLsizei depth = getBaseLevelDepth();
2128
2129 if (width <= 0 || height <= 0 || depth <= 0)
2130 {
2131 return false;
2132 }
2133
2134 if (level == 0)
2135 {
2136 return true;
2137 }
2138
2139 ImageD3D *levelImage = mImageArray[level];
2140
2141 if (levelImage->getInternalFormat() != getBaseLevelInternalFormat())
2142 {
2143 return false;
2144 }
2145
2146 if (levelImage->getWidth() != std::max(1, width >> level))
2147 {
2148 return false;
2149 }
2150
2151 if (levelImage->getHeight() != std::max(1, height >> level))
2152 {
2153 return false;
2154 }
2155
2156 if (levelImage->getDepth() != std::max(1, depth >> level))
2157 {
2158 return false;
2159 }
2160
2161 return true;
2162}
2163
Jamie Madille76bdda2014-10-20 17:13:52 -04002164bool TextureD3D_3D::isImageComplete(const gl::ImageIndex &index) const
2165{
2166 return isLevelComplete(index.mipIndex);
2167}
2168
Geoff Langef7b0162014-09-04 13:29:23 -04002169gl::Error TextureD3D_3D::updateStorageLevel(int level)
Brandon Jones78b1acd2014-07-15 15:33:07 -07002170{
2171 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
2172 ASSERT(isLevelComplete(level));
2173
2174 if (mImageArray[level]->isDirty())
2175 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002176 gl::ImageIndex index = gl::ImageIndex::Make3D(level);
2177 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
Geoff Langef7b0162014-09-04 13:29:23 -04002178 gl::Error error = commitRegion(index, region);
2179 if (error.isError())
2180 {
2181 return error;
2182 }
Brandon Jones78b1acd2014-07-15 15:33:07 -07002183 }
Geoff Langef7b0162014-09-04 13:29:23 -04002184
2185 return gl::Error(GL_NO_ERROR);
Brandon Jones78b1acd2014-07-15 15:33:07 -07002186}
2187
2188void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2189{
2190 // If there currently is a corresponding storage texture image, it has these parameters
2191 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2192 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
2193 const int storageDepth = std::max(1, getBaseLevelDepth() >> level);
2194 const GLenum storageFormat = getBaseLevelInternalFormat();
2195
2196 mImageArray[level]->redefine(mRenderer, GL_TEXTURE_3D, internalformat, width, height, depth, false);
2197
2198 if (mTexStorage)
2199 {
2200 const int storageLevels = mTexStorage->getLevelCount();
2201
2202 if ((level >= storageLevels && storageLevels != 0) ||
2203 width != storageWidth ||
2204 height != storageHeight ||
2205 depth != storageDepth ||
2206 internalformat != storageFormat) // Discard mismatched storage
2207 {
2208 for (int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
2209 {
2210 mImageArray[i]->markDirty();
2211 }
2212
2213 SafeDelete(mTexStorage);
2214 mDirtyImages = true;
2215 }
2216 }
2217}
2218
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002219gl::ImageIndexIterator TextureD3D_3D::imageIterator() const
2220{
2221 return gl::ImageIndexIterator::Make3D(0, mTexStorage->getLevelCount(),
2222 gl::ImageIndex::ENTIRE_LEVEL, gl::ImageIndex::ENTIRE_LEVEL);
2223}
Brandon Jones142ec422014-07-16 10:31:30 -07002224
Jamie Madillcb83dc12014-09-29 10:46:12 -04002225gl::ImageIndex TextureD3D_3D::getImageIndex(GLint mip, GLint /*layer*/) const
2226{
2227 // The "layer" here does not apply to 3D images. We use one Image per mip.
2228 return gl::ImageIndex::Make3D(mip);
2229}
2230
Jamie Madill710e5772014-10-20 17:13:53 -04002231bool TextureD3D_3D::isValidIndex(const gl::ImageIndex &index) const
2232{
2233 return (mTexStorage && index.type == GL_TEXTURE_3D &&
2234 index.mipIndex >= 0 && index.mipIndex < mTexStorage->getLevelCount());
2235}
2236
Jamie Madill93e13fb2014-11-06 15:27:25 -05002237TextureD3D_2DArray::TextureD3D_2DArray(RendererD3D *renderer)
Jamie Madill98553e32014-09-30 16:33:50 -04002238 : TextureD3D(renderer)
Brandon Jones142ec422014-07-16 10:31:30 -07002239{
2240 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2241 {
2242 mLayerCounts[level] = 0;
2243 mImageArray[level] = NULL;
2244 }
2245}
2246
2247TextureD3D_2DArray::~TextureD3D_2DArray()
2248{
Austin Kinross69822602014-08-12 15:51:37 -07002249 // Delete the Images before the TextureStorage.
2250 // Images might be relying on the TextureStorage for some of their data.
2251 // 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 -07002252 deleteImages();
Austin Kinross69822602014-08-12 15:51:37 -07002253 SafeDelete(mTexStorage);
Brandon Jones142ec422014-07-16 10:31:30 -07002254}
2255
Brandon Jones142ec422014-07-16 10:31:30 -07002256Image *TextureD3D_2DArray::getImage(int level, int layer) const
2257{
2258 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2259 ASSERT(layer < mLayerCounts[level]);
2260 return mImageArray[level][layer];
2261}
2262
Jamie Madillfeda4d22014-09-17 13:03:29 -04002263Image *TextureD3D_2DArray::getImage(const gl::ImageIndex &index) const
2264{
2265 ASSERT(index.mipIndex < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2266 ASSERT(index.layerIndex < mLayerCounts[index.mipIndex]);
2267 ASSERT(index.type == GL_TEXTURE_2D_ARRAY);
2268 return mImageArray[index.mipIndex][index.layerIndex];
2269}
2270
Brandon Jones142ec422014-07-16 10:31:30 -07002271GLsizei TextureD3D_2DArray::getLayerCount(int level) const
2272{
2273 ASSERT(level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
2274 return mLayerCounts[level];
2275}
2276
Brandon Jones142ec422014-07-16 10:31:30 -07002277GLsizei TextureD3D_2DArray::getWidth(GLint level) const
2278{
2279 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getWidth() : 0;
2280}
2281
2282GLsizei TextureD3D_2DArray::getHeight(GLint level) const
2283{
2284 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getHeight() : 0;
2285}
2286
Brandon Jones142ec422014-07-16 10:31:30 -07002287GLenum TextureD3D_2DArray::getInternalFormat(GLint level) const
2288{
2289 return (level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS && mLayerCounts[level] > 0) ? mImageArray[level][0]->getInternalFormat() : GL_NONE;
2290}
2291
2292bool TextureD3D_2DArray::isDepth(GLint level) const
2293{
Geoff Lang5d601382014-07-22 15:14:06 -04002294 return gl::GetInternalFormatInfo(getInternalFormat(level)).depthBits > 0;
Brandon Jones142ec422014-07-16 10:31:30 -07002295}
2296
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002297gl::Error TextureD3D_2DArray::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
2298 GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
2299 const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002300{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002301 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2302
Geoff Lang5d601382014-07-22 15:14:06 -04002303 GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
2304
Brandon Jones142ec422014-07-16 10:31:30 -07002305 redefineImage(level, sizedInternalFormat, width, height, depth);
2306
Geoff Lang5d601382014-07-22 15:14:06 -04002307 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
2308 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002309
2310 for (int i = 0; i < depth; i++)
2311 {
2312 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillba6bc952014-10-06 10:56:22 -04002313 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
2314 gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002315 if (error.isError())
2316 {
2317 return error;
2318 }
Brandon Jones142ec422014-07-16 10:31:30 -07002319 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002320
2321 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002322}
2323
Geoff Langb5348332014-09-02 13:16:34 -04002324gl::Error TextureD3D_2DArray::setCompressedImage(GLenum target, GLint level, GLenum format,
2325 GLsizei width, GLsizei height, GLsizei depth,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002326 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002327{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002328 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2329
Brandon Jones142ec422014-07-16 10:31:30 -07002330 // compressed formats don't have separate sized internal formats-- we can just use the compressed format directly
2331 redefineImage(level, format, width, height, depth);
2332
Geoff Lang5d601382014-07-22 15:14:06 -04002333 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2334 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002335
2336 for (int i = 0; i < depth; i++)
2337 {
2338 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
Jamie Madillc751d1e2014-10-21 17:46:29 -04002339 gl::Error error = TextureD3D::setCompressedImage(unpack, imageSize, layerPixels, mImageArray[level][i]);
Geoff Langb5348332014-09-02 13:16:34 -04002340 if (error.isError())
2341 {
2342 return error;
2343 }
Brandon Jones142ec422014-07-16 10:31:30 -07002344 }
Geoff Langb5348332014-09-02 13:16:34 -04002345
2346 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002347}
2348
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002349gl::Error TextureD3D_2DArray::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2350 GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
2351 const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002352{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002353 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2354
Geoff Lang5d601382014-07-22 15:14:06 -04002355 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(getInternalFormat(level));
2356 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
Brandon Jones142ec422014-07-16 10:31:30 -07002357
2358 for (int i = 0; i < depth; i++)
2359 {
2360 int layer = zoffset + i;
2361 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2362
Jamie Madillfeda4d22014-09-17 13:03:29 -04002363 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
Jamie Madille6b6da02014-10-02 11:03:14 -04002364 gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
2365 unpack, layerPixels, index);
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002366 if (error.isError())
2367 {
2368 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002369 }
2370 }
Geoff Lang1ba6b8d2014-08-28 10:57:31 -04002371
2372 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002373}
2374
Geoff Langb5348332014-09-02 13:16:34 -04002375gl::Error TextureD3D_2DArray::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
2376 GLsizei width, GLsizei height, GLsizei depth, GLenum format,
Jamie Madillc751d1e2014-10-21 17:46:29 -04002377 GLsizei imageSize, const gl::PixelUnpackState &unpack, const void *pixels)
Brandon Jones142ec422014-07-16 10:31:30 -07002378{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002379 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2380
Geoff Lang5d601382014-07-22 15:14:06 -04002381 const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(format);
2382 GLsizei inputDepthPitch = formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, width, height, 1);
Brandon Jones142ec422014-07-16 10:31:30 -07002383
2384 for (int i = 0; i < depth; i++)
2385 {
2386 int layer = zoffset + i;
2387 const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
2388
Jamie Madillc751d1e2014-10-21 17:46:29 -04002389 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 -04002390 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002391 {
Geoff Langb5348332014-09-02 13:16:34 -04002392 return error;
2393 }
2394
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002395 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2396 gl::Box region(xoffset, yoffset, 0, width, height, 1);
2397 error = commitRegion(index, region);
Geoff Langb5348332014-09-02 13:16:34 -04002398 if (error.isError())
2399 {
2400 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002401 }
2402 }
Geoff Langb5348332014-09-02 13:16:34 -04002403
2404 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002405}
2406
Geoff Langef7b0162014-09-04 13:29:23 -04002407gl::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 -07002408{
2409 UNIMPLEMENTED();
Geoff Langef7b0162014-09-04 13:29:23 -04002410 return gl::Error(GL_INVALID_OPERATION, "Copying 2D array textures is unimplemented.");
Brandon Jonescef06ff2014-08-05 13:27:48 -07002411}
2412
Geoff Langef7b0162014-09-04 13:29:23 -04002413gl::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 -07002414{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002415 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2416
Jamie Madill82bf0c52014-10-03 11:50:53 -04002417 gl::Rectangle sourceRect(x, y, width, height);
Jamie Madille76bdda2014-10-20 17:13:52 -04002418 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, zoffset);
Jamie Madill82bf0c52014-10-03 11:50:53 -04002419
Jamie Madille76bdda2014-10-20 17:13:52 -04002420 if (canCreateRenderTargetForImage(index))
Brandon Jones142ec422014-07-16 10:31:30 -07002421 {
Geoff Langef7b0162014-09-04 13:29:23 -04002422 gl::Error error = mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
2423 if (error.isError())
2424 {
2425 return error;
2426 }
2427
Brandon Jones142ec422014-07-16 10:31:30 -07002428 mDirtyImages = true;
2429 }
2430 else
2431 {
Geoff Langef7b0162014-09-04 13:29:23 -04002432 gl::Error error = ensureRenderTarget();
2433 if (error.isError())
2434 {
2435 return error;
2436 }
Brandon Jones142ec422014-07-16 10:31:30 -07002437
2438 if (isValidLevel(level))
2439 {
Geoff Langef7b0162014-09-04 13:29:23 -04002440 error = updateStorageLevel(level);
2441 if (error.isError())
2442 {
2443 return error;
2444 }
Brandon Jones142ec422014-07-16 10:31:30 -07002445
Geoff Langef7b0162014-09-04 13:29:23 -04002446 error = mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
2447 xoffset, yoffset, zoffset, mTexStorage, level);
2448 if (error.isError())
2449 {
2450 return error;
2451 }
Brandon Jones142ec422014-07-16 10:31:30 -07002452 }
2453 }
Geoff Langef7b0162014-09-04 13:29:23 -04002454 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002455}
2456
Geoff Lang1f8532b2014-09-05 09:46:13 -04002457gl::Error TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Brandon Jones142ec422014-07-16 10:31:30 -07002458{
Brandon Jonescef06ff2014-08-05 13:27:48 -07002459 ASSERT(target == GL_TEXTURE_2D_ARRAY);
2460
Brandon Jones142ec422014-07-16 10:31:30 -07002461 deleteImages();
2462
2463 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2464 {
2465 GLsizei levelWidth = std::max(1, width >> level);
2466 GLsizei levelHeight = std::max(1, height >> level);
2467
2468 mLayerCounts[level] = (level < levels ? depth : 0);
2469
2470 if (mLayerCounts[level] > 0)
2471 {
2472 // Create new images for this level
2473 mImageArray[level] = new ImageD3D*[mLayerCounts[level]];
2474
2475 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2476 {
2477 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2478 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, levelWidth,
2479 levelHeight, 1, true);
2480 }
2481 }
2482 }
2483
Geoff Lang1f8532b2014-09-05 09:46:13 -04002484 // TODO(geofflang): Verify storage creation had no errors
Jamie Madillc4833262014-09-18 16:18:26 -04002485 bool renderTarget = IsRenderTargetUsage(mUsage);
2486 TextureStorage *storage = mRenderer->createTextureStorage2DArray(internalformat, renderTarget, width, height, depth, levels);
Geoff Lang1f8532b2014-09-05 09:46:13 -04002487
2488 gl::Error error = setCompleteTexStorage(storage);
2489 if (error.isError())
2490 {
2491 SafeDelete(storage);
2492 return error;
2493 }
2494
2495 mImmutable = true;
2496
2497 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002498}
2499
Brandon Jones6053a522014-07-25 16:22:09 -07002500void TextureD3D_2DArray::bindTexImage(egl::Surface *surface)
Brandon Jones142ec422014-07-16 10:31:30 -07002501{
Brandon Jones6053a522014-07-25 16:22:09 -07002502 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002503}
2504
Brandon Jones6053a522014-07-25 16:22:09 -07002505void TextureD3D_2DArray::releaseTexImage()
Brandon Jones142ec422014-07-16 10:31:30 -07002506{
Brandon Jones6053a522014-07-25 16:22:09 -07002507 UNREACHABLE();
Brandon Jones142ec422014-07-16 10:31:30 -07002508}
2509
Brandon Jones6053a522014-07-25 16:22:09 -07002510
Jamie Madill4aa79e12014-09-29 10:46:14 -04002511void TextureD3D_2DArray::initMipmapsImages()
Brandon Jones142ec422014-07-16 10:31:30 -07002512{
2513 int baseWidth = getBaseLevelWidth();
2514 int baseHeight = getBaseLevelHeight();
2515 int baseDepth = getBaseLevelDepth();
2516 GLenum baseFormat = getBaseLevelInternalFormat();
2517
2518 // Purge array levels 1 through q and reset them to represent the generated mipmap levels.
2519 int levelCount = mipLevels();
2520 for (int level = 1; level < levelCount; level++)
2521 {
2522 redefineImage(level, baseFormat, std::max(baseWidth >> level, 1), std::max(baseHeight >> level, 1), baseDepth);
2523 }
Brandon Jones142ec422014-07-16 10:31:30 -07002524}
2525
Jamie Madillac7579c2014-09-17 16:59:33 -04002526unsigned int TextureD3D_2DArray::getRenderTargetSerial(const gl::ImageIndex &index)
Brandon Jones142ec422014-07-16 10:31:30 -07002527{
Geoff Langef7b0162014-09-04 13:29:23 -04002528 return (!ensureRenderTarget().isError() ? mTexStorage->getRenderTargetSerial(index) : 0);
Brandon Jones142ec422014-07-16 10:31:30 -07002529}
2530
Geoff Lang64f23f62014-09-10 14:40:12 -04002531gl::Error TextureD3D_2DArray::getRenderTarget(const gl::ImageIndex &index, RenderTarget **outRT)
Brandon Jones142ec422014-07-16 10:31:30 -07002532{
2533 // ensure the underlying texture is created
Geoff Langef7b0162014-09-04 13:29:23 -04002534 gl::Error error = ensureRenderTarget();
2535 if (error.isError())
Brandon Jones142ec422014-07-16 10:31:30 -07002536 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002537 return error;
Brandon Jones142ec422014-07-16 10:31:30 -07002538 }
2539
Geoff Langef7b0162014-09-04 13:29:23 -04002540 error = updateStorageLevel(index.mipIndex);
2541 if (error.isError())
2542 {
Geoff Lang64f23f62014-09-10 14:40:12 -04002543 return error;
Geoff Langef7b0162014-09-04 13:29:23 -04002544 }
2545
Geoff Lang64f23f62014-09-10 14:40:12 -04002546 return mTexStorage->getRenderTarget(index, outRT);
Brandon Jones142ec422014-07-16 10:31:30 -07002547}
2548
Geoff Langef7b0162014-09-04 13:29:23 -04002549gl::Error TextureD3D_2DArray::initializeStorage(bool renderTarget)
Brandon Jones142ec422014-07-16 10:31:30 -07002550{
2551 // Only initialize the first time this texture is used as a render target or shader resource
2552 if (mTexStorage)
2553 {
Geoff Langef7b0162014-09-04 13:29:23 -04002554 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002555 }
2556
2557 // do not attempt to create storage for nonexistant data
2558 if (!isLevelComplete(0))
2559 {
Geoff Langef7b0162014-09-04 13:29:23 -04002560 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002561 }
2562
2563 bool createRenderTarget = (renderTarget || mUsage == GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
2564
Geoff Langef7b0162014-09-04 13:29:23 -04002565 TextureStorage *storage = NULL;
2566 gl::Error error = createCompleteStorage(createRenderTarget, &storage);
2567 if (error.isError())
2568 {
2569 return error;
2570 }
2571
2572 error = setCompleteTexStorage(storage);
2573 if (error.isError())
2574 {
2575 SafeDelete(storage);
2576 return error;
2577 }
2578
Brandon Jones142ec422014-07-16 10:31:30 -07002579 ASSERT(mTexStorage);
2580
2581 // flush image data to the storage
Geoff Langef7b0162014-09-04 13:29:23 -04002582 error = updateStorage();
2583 if (error.isError())
2584 {
2585 return error;
2586 }
2587
2588 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002589}
2590
Geoff Langef7b0162014-09-04 13:29:23 -04002591gl::Error TextureD3D_2DArray::createCompleteStorage(bool renderTarget, TextureStorage **outStorage) const
Brandon Jones142ec422014-07-16 10:31:30 -07002592{
2593 GLsizei width = getBaseLevelWidth();
2594 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002595 GLsizei depth = getLayerCount(0);
Jamie Madillc4833262014-09-18 16:18:26 -04002596 GLenum internalFormat = getBaseLevelInternalFormat();
Brandon Jones142ec422014-07-16 10:31:30 -07002597
2598 ASSERT(width > 0 && height > 0 && depth > 0);
2599
2600 // use existing storage level count, when previously specified by TexStorage*D
2601 GLint levels = (mTexStorage ? mTexStorage->getLevelCount() : creationLevels(width, height, 1));
2602
Geoff Langef7b0162014-09-04 13:29:23 -04002603 // TODO(geofflang): Verify storage creation succeeds
2604 *outStorage = mRenderer->createTextureStorage2DArray(internalFormat, renderTarget, width, height, depth, levels);
2605
2606 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002607}
2608
Geoff Langef7b0162014-09-04 13:29:23 -04002609gl::Error TextureD3D_2DArray::setCompleteTexStorage(TextureStorage *newCompleteTexStorage)
Brandon Jones142ec422014-07-16 10:31:30 -07002610{
2611 SafeDelete(mTexStorage);
2612 mTexStorage = newCompleteTexStorage;
2613 mDirtyImages = true;
2614
2615 // We do not support managed 2D array storage, as managed storage is ES2/D3D9 only
2616 ASSERT(!mTexStorage->isManaged());
Geoff Langef7b0162014-09-04 13:29:23 -04002617
2618 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002619}
2620
Geoff Langef7b0162014-09-04 13:29:23 -04002621gl::Error TextureD3D_2DArray::updateStorage()
Brandon Jones142ec422014-07-16 10:31:30 -07002622{
2623 ASSERT(mTexStorage != NULL);
2624 GLint storageLevels = mTexStorage->getLevelCount();
2625 for (int level = 0; level < storageLevels; level++)
2626 {
2627 if (isLevelComplete(level))
2628 {
Geoff Langef7b0162014-09-04 13:29:23 -04002629 gl::Error error = updateStorageLevel(level);
2630 if (error.isError())
2631 {
2632 return error;
2633 }
Brandon Jones142ec422014-07-16 10:31:30 -07002634 }
2635 }
Geoff Langef7b0162014-09-04 13:29:23 -04002636
2637 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002638}
2639
Brandon Jones142ec422014-07-16 10:31:30 -07002640bool TextureD3D_2DArray::isValidLevel(int level) const
2641{
2642 return (mTexStorage ? (level >= 0 && level < mTexStorage->getLevelCount()) : 0);
2643}
2644
2645bool TextureD3D_2DArray::isLevelComplete(int level) const
2646{
2647 ASSERT(level >= 0 && level < (int)ArraySize(mImageArray));
2648
2649 if (isImmutable())
2650 {
2651 return true;
2652 }
2653
2654 GLsizei width = getBaseLevelWidth();
2655 GLsizei height = getBaseLevelHeight();
Jamie Madill3269bcb2014-09-30 16:33:52 -04002656 GLsizei layers = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002657
2658 if (width <= 0 || height <= 0 || layers <= 0)
2659 {
2660 return false;
2661 }
2662
2663 if (level == 0)
2664 {
2665 return true;
2666 }
2667
2668 if (getInternalFormat(level) != getInternalFormat(0))
2669 {
2670 return false;
2671 }
2672
2673 if (getWidth(level) != std::max(1, width >> level))
2674 {
2675 return false;
2676 }
2677
2678 if (getHeight(level) != std::max(1, height >> level))
2679 {
2680 return false;
2681 }
2682
Jamie Madill3269bcb2014-09-30 16:33:52 -04002683 if (getLayerCount(level) != layers)
Brandon Jones142ec422014-07-16 10:31:30 -07002684 {
2685 return false;
2686 }
2687
2688 return true;
2689}
2690
Jamie Madille76bdda2014-10-20 17:13:52 -04002691bool TextureD3D_2DArray::isImageComplete(const gl::ImageIndex &index) const
2692{
2693 return isLevelComplete(index.mipIndex);
2694}
2695
Geoff Langef7b0162014-09-04 13:29:23 -04002696gl::Error TextureD3D_2DArray::updateStorageLevel(int level)
Brandon Jones142ec422014-07-16 10:31:30 -07002697{
2698 ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
2699 ASSERT(isLevelComplete(level));
2700
2701 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2702 {
2703 ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
2704 if (mImageArray[level][layer]->isDirty())
2705 {
Jamie Madill7cb2b9d2014-10-02 11:03:13 -04002706 gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
2707 gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
Geoff Langef7b0162014-09-04 13:29:23 -04002708 gl::Error error = commitRegion(index, region);
2709 if (error.isError())
2710 {
2711 return error;
2712 }
Brandon Jones142ec422014-07-16 10:31:30 -07002713 }
2714 }
Geoff Langef7b0162014-09-04 13:29:23 -04002715
2716 return gl::Error(GL_NO_ERROR);
Brandon Jones142ec422014-07-16 10:31:30 -07002717}
2718
2719void TextureD3D_2DArray::deleteImages()
2720{
2721 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
2722 {
2723 for (int layer = 0; layer < mLayerCounts[level]; ++layer)
2724 {
2725 delete mImageArray[level][layer];
2726 }
2727 delete[] mImageArray[level];
2728 mImageArray[level] = NULL;
2729 mLayerCounts[level] = 0;
2730 }
2731}
2732
2733void TextureD3D_2DArray::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
2734{
2735 // If there currently is a corresponding storage texture image, it has these parameters
2736 const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
2737 const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
Jamie Madill3269bcb2014-09-30 16:33:52 -04002738 const int storageDepth = getLayerCount(0);
Brandon Jones142ec422014-07-16 10:31:30 -07002739 const GLenum storageFormat = getBaseLevelInternalFormat();
2740
2741 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2742 {
2743 delete mImageArray[level][layer];
2744 }
2745 delete[] mImageArray[level];
2746 mImageArray[level] = NULL;
2747 mLayerCounts[level] = depth;
2748
2749 if (depth > 0)
2750 {
2751 mImageArray[level] = new ImageD3D*[depth]();
2752
2753 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2754 {
2755 mImageArray[level][layer] = ImageD3D::makeImageD3D(mRenderer->createImage());
2756 mImageArray[level][layer]->redefine(mRenderer, GL_TEXTURE_2D_ARRAY, internalformat, width, height, 1, false);
2757 }
2758 }
2759
2760 if (mTexStorage)
2761 {
2762 const int storageLevels = mTexStorage->getLevelCount();
2763
2764 if ((level >= storageLevels && storageLevels != 0) ||
2765 width != storageWidth ||
2766 height != storageHeight ||
2767 depth != storageDepth ||
2768 internalformat != storageFormat) // Discard mismatched storage
2769 {
2770 for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; level++)
2771 {
2772 for (int layer = 0; layer < mLayerCounts[level]; layer++)
2773 {
2774 mImageArray[level][layer]->markDirty();
2775 }
2776 }
2777
2778 delete mTexStorage;
2779 mTexStorage = NULL;
2780 mDirtyImages = true;
2781 }
2782 }
2783}
2784
Jamie Madillef4ac5b2014-09-29 10:46:11 -04002785gl::ImageIndexIterator TextureD3D_2DArray::imageIterator() const
2786{
2787 return gl::ImageIndexIterator::Make2DArray(0, mTexStorage->getLevelCount(), mLayerCounts);
2788}
2789
Jamie Madillcb83dc12014-09-29 10:46:12 -04002790gl::ImageIndex TextureD3D_2DArray::getImageIndex(GLint mip, GLint layer) const
2791{
2792 return gl::ImageIndex::Make2DArray(mip, layer);
2793}
2794
Jamie Madill710e5772014-10-20 17:13:53 -04002795bool TextureD3D_2DArray::isValidIndex(const gl::ImageIndex &index) const
2796{
2797 // Check for having a storage and the right type of index
2798 if (!mTexStorage || index.type != GL_TEXTURE_2D_ARRAY)
2799 {
2800 return false;
2801 }
2802
2803 // Check the mip index
2804 if (index.mipIndex < 0 || index.mipIndex >= mTexStorage->getLevelCount())
2805 {
2806 return false;
2807 }
2808
2809 // Check the layer index
2810 return (!index.hasLayer() || (index.layerIndex >= 0 && index.layerIndex < mLayerCounts[index.mipIndex]));
2811}
2812
Brandon Jones78b1acd2014-07-15 15:33:07 -07002813}