Texture3D copy to level

Bug 19126833

Change-Id: I6da0f1a3d09ab8f510f6f5b2600d911095e02a43
Reviewed-on: https://swiftshader-review.googlesource.com/2200
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGL/Context.cpp b/src/OpenGL/libGL/Context.cpp
index fbc05af..d1b36ea 100644
--- a/src/OpenGL/libGL/Context.cpp
+++ b/src/OpenGL/libGL/Context.cpp
@@ -2094,7 +2094,7 @@
 				device->setTextureFilter(samplerType, samplerIndex, minFilter);

 			//	device->setTextureFilter(samplerType, samplerIndex, es2sw::ConvertMagFilter(magFilter));

 				device->setMipmapFilter(samplerType, samplerIndex, mipFilter);

-				device->setMaxAnisotropy(samplerType, samplerIndex, (int)maxAnisotropy);

+				device->setMaxAnisotropy(samplerType, samplerIndex, maxAnisotropy);

 

 				applyTexture(samplerType, samplerIndex, texture);

 

@@ -2834,8 +2834,8 @@
         return error(GL_INVALID_OPERATION);

     }

 

-    sw::Rect sourceRect;

-    sw::Rect destRect;

+    sw::SliceRect sourceRect;

+    sw::SliceRect destRect;

 

     if(srcX0 < srcX1)

     {

diff --git a/src/OpenGL/libGL/Device.cpp b/src/OpenGL/libGL/Device.cpp
index fb1fb4b..7e78042 100644
--- a/src/OpenGL/libGL/Device.cpp
+++ b/src/OpenGL/libGL/Device.cpp
@@ -490,7 +490,7 @@
 		this->viewport = viewport;

 	}

 

-	bool Device::stretchRect(Image *source, const sw::Rect *sourceRect, Image *dest, const sw::Rect *destRect, bool filter)

+	bool Device::stretchRect(Image *source, const sw::SliceRect *sourceRect, Image *dest, const sw::SliceRect *destRect, bool filter)

 	{

 		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

 		{

@@ -503,8 +503,8 @@
 		int dWidth = dest->getExternalWidth();

 		int dHeight = dest->getExternalHeight();

 

-		Rect sRect;

-		Rect dRect;

+		SliceRect sRect;

+		SliceRect dRect;

 

 		if(sourceRect)

 		{

@@ -546,8 +546,8 @@
 		{

 			if(source->hasDepth())

 			{

-				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);

-				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);

+				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sRect.slice, LOCK_READONLY, PUBLIC);

+				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, dRect.slice, LOCK_DISCARD, PUBLIC);

 

 				unsigned int width = source->getInternalWidth();

 				unsigned int height = source->getInternalHeight();

@@ -588,8 +588,8 @@
 		}

 		else if(!scaling && equalFormats)

 		{

-			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);

-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);

+			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sRect.slice, LOCK_READONLY, PUBLIC);

+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, LOCK_READWRITE, PUBLIC);

 			unsigned int sourcePitch = source->getInternalPitchB();

 			unsigned int destPitch = dest->getInternalPitchB();

 

diff --git a/src/OpenGL/libGL/Device.hpp b/src/OpenGL/libGL/Device.hpp
index 142c5fb..09c566e 100644
--- a/src/OpenGL/libGL/Device.hpp
+++ b/src/OpenGL/libGL/Device.hpp
@@ -65,7 +65,7 @@
 		virtual void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);

 		virtual void setViewport(const Viewport &viewport);

 

-		virtual bool stretchRect(Image *sourceSurface, const sw::Rect *sourceRect, Image *destSurface, const sw::Rect *destRect, bool filter);

+		virtual bool stretchRect(Image *sourceSurface, const sw::SliceRect *sourceRect, Image *destSurface, const sw::SliceRect *destRect, bool filter);

 		virtual void finish();

 

 	private:

diff --git a/src/OpenGL/libGL/Texture.cpp b/src/OpenGL/libGL/Texture.cpp
index fd4d29c..137b39f 100644
--- a/src/OpenGL/libGL/Texture.cpp
+++ b/src/OpenGL/libGL/Texture.cpp
@@ -239,8 +239,9 @@
 {

     Device *device = getDevice();

 	

-    sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};

-    bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);

+    sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), 0);

+    sw::SliceRect sourceSliceRect(sourceRect);

+    bool success = device->stretchRect(source, &sourceSliceRect, dest, &destRect, false);

 

     if(!success)

     {

diff --git a/src/OpenGL/libGL/libGL.cpp b/src/OpenGL/libGL/libGL.cpp
index 30cf880..e1cc68f 100644
--- a/src/OpenGL/libGL/libGL.cpp
+++ b/src/OpenGL/libGL/libGL.cpp
@@ -5971,7 +5971,7 @@
 

 	if(context)

 	{

-		for(int i = list; i < list + range; i++)

+		for(GLuint i = list; i < list + range; i++)

 		{

 			context->deleteList(i);

 		}

diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 52e169d..6aab251 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -408,7 +408,7 @@
 		this->viewport = viewport;

 	}

 

-	bool Device::stretchRect(egl::Image *source, const sw::Rect *sourceRect, egl::Image *dest, const sw::Rect *destRect, bool filter)

+	bool Device::stretchRect(egl::Image *source, const sw::SliceRect *sourceRect, egl::Image *dest, const sw::SliceRect *destRect, bool filter)

 	{

 		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

 		{

@@ -421,8 +421,8 @@
 		int dWidth = dest->getExternalWidth();

 		int dHeight = dest->getExternalHeight();

 

-		Rect sRect;

-		Rect dRect;

+		SliceRect sRect;

+		SliceRect dRect;

 

 		if(sourceRect)

 		{

@@ -464,8 +464,8 @@
 		{

 			if(source->hasDepth())

 			{

-				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);

-				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);

+				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sRect.slice, LOCK_READONLY, PUBLIC);

+				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, dRect.slice, LOCK_DISCARD, PUBLIC);

 

 				unsigned int width = source->getInternalWidth();

 				unsigned int height = source->getInternalHeight();

@@ -506,8 +506,8 @@
 		}

 		else if(!scaling && equalFormats)

 		{

-			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);

-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);

+			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sRect.slice, LOCK_READONLY, PUBLIC);

+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, LOCK_READWRITE, PUBLIC);

 			unsigned int sourcePitch = source->getInternalPitchB();

 			unsigned int destPitch = dest->getInternalPitchB();

 

diff --git a/src/OpenGL/libGLES_CM/Device.hpp b/src/OpenGL/libGLES_CM/Device.hpp
index 9ccdeca..8790154 100644
--- a/src/OpenGL/libGLES_CM/Device.hpp
+++ b/src/OpenGL/libGLES_CM/Device.hpp
@@ -65,7 +65,7 @@
 		virtual void setScissorRect(const sw::Rect &rect);

 		virtual void setViewport(const Viewport &viewport);

 

-		virtual bool stretchRect(egl::Image *sourceSurface, const sw::Rect *sourceRect, egl::Image *destSurface, const sw::Rect *destRect, bool filter);

+		virtual bool stretchRect(egl::Image *sourceSurface, const sw::SliceRect *sourceRect, egl::Image *destSurface, const sw::SliceRect *destRect, bool filter);

 		virtual void finish();

 

 	private:

diff --git a/src/OpenGL/libGLES_CM/Texture.cpp b/src/OpenGL/libGLES_CM/Texture.cpp
index fbb151f..9ec5dd3 100644
--- a/src/OpenGL/libGLES_CM/Texture.cpp
+++ b/src/OpenGL/libGLES_CM/Texture.cpp
@@ -252,8 +252,9 @@
 {

     Device *device = getDevice();

 	

-    sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};

-    bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);

+    sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), 0);

+    sw::SliceRect sourceSliceRect(sourceRect);

+    bool success = device->stretchRect(source, &sourceSliceRect, dest, &destRect, false);

 

     if(!success)

     {

diff --git a/src/OpenGL/libGLESv2/Context.cpp b/src/OpenGL/libGLESv2/Context.cpp
index a141b26..586f238 100644
--- a/src/OpenGL/libGLESv2/Context.cpp
+++ b/src/OpenGL/libGLESv2/Context.cpp
@@ -2874,8 +2874,8 @@
         return error(GL_INVALID_OPERATION);

     }

 

-    sw::Rect sourceRect;

-    sw::Rect destRect;

+    sw::SliceRect sourceRect;

+    sw::SliceRect destRect;

 

     if(srcX0 < srcX1)

     {

diff --git a/src/OpenGL/libGLESv2/Device.cpp b/src/OpenGL/libGLESv2/Device.cpp
index 777cbd4..edeb0d7 100644
--- a/src/OpenGL/libGLESv2/Device.cpp
+++ b/src/OpenGL/libGLESv2/Device.cpp
@@ -470,7 +470,7 @@
 		this->viewport = viewport;

 	}

 

-	bool Device::stretchRect(egl::Image *source, const sw::Rect *sourceRect, egl::Image *dest, const sw::Rect *destRect, bool filter)

+	bool Device::stretchRect(egl::Image *source, const sw::SliceRect *sourceRect, egl::Image *dest, const sw::SliceRect *destRect, bool filter)

 	{

 		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

 		{

@@ -483,8 +483,8 @@
 		int dWidth = dest->getExternalWidth();

 		int dHeight = dest->getExternalHeight();

 

-		Rect sRect;

-		Rect dRect;

+		SliceRect sRect;

+		SliceRect dRect;

 

 		if(sourceRect)

 		{

@@ -526,8 +526,8 @@
 		{

 			if(source->hasDepth())

 			{

-				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);

-				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);

+				sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sourceRect->slice, LOCK_READONLY, PUBLIC);

+				sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, destRect->slice, LOCK_DISCARD, PUBLIC);

 

 				unsigned int width = source->getInternalWidth();

 				unsigned int height = source->getInternalHeight();

@@ -568,8 +568,8 @@
 		}

 		else if(!scaling && equalFormats)

 		{

-			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);

-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);

+			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);

+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, LOCK_READWRITE, PUBLIC);

 			unsigned int sourcePitch = source->getInternalPitchB();

 			unsigned int destPitch = dest->getInternalPitchB();

 

diff --git a/src/OpenGL/libGLESv2/Device.hpp b/src/OpenGL/libGLESv2/Device.hpp
index 92a3a11..4dbe2e5 100644
--- a/src/OpenGL/libGLESv2/Device.hpp
+++ b/src/OpenGL/libGLESv2/Device.hpp
@@ -69,7 +69,7 @@
 		virtual void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);

 		virtual void setViewport(const Viewport &viewport);

 

-		virtual bool stretchRect(egl::Image *sourceSurface, const sw::Rect *sourceRect, egl::Image *destSurface, const sw::Rect *destRect, bool filter);

+		virtual bool stretchRect(egl::Image *sourceSurface, const sw::SliceRect *sourceRect, egl::Image *destSurface, const sw::SliceRect *destRect, bool filter);

 		virtual void finish();

 

 	private:

diff --git a/src/OpenGL/libGLESv2/Texture.cpp b/src/OpenGL/libGLESv2/Texture.cpp
index 9cfc422..cdacf10 100644
--- a/src/OpenGL/libGLESv2/Texture.cpp
+++ b/src/OpenGL/libGLESv2/Texture.cpp
@@ -281,11 +281,11 @@
     }

 }

 

-bool Texture::copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest)

+bool Texture::copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest)

 {

     Device *device = getDevice();

 	

-    sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};

+    sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), zoffset);

     bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);

 

     if(!success)

@@ -532,10 +532,10 @@
 

     if(width != 0 && height != 0)

     {

-		sw::Rect sourceRect = {x, y, x + width, y + height};

+		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);

 		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

 

-        copy(renderTarget, sourceRect, format, 0, 0, image[level]);

+        copy(renderTarget, sourceRect, format, 0, 0, 0, image[level]);

     }

 

 	renderTarget->release();

@@ -548,7 +548,7 @@
 		return error(GL_INVALID_OPERATION);

 	}

 

-    if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())

+    if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset != 0)

     {

         return error(GL_INVALID_VALUE);

     }

@@ -561,10 +561,10 @@
         return error(GL_OUT_OF_MEMORY);

     }

 

-	sw::Rect sourceRect = {x, y, x + width, y + height};

+	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);

 	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

 

-	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);

+	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);

 

 	renderTarget->release();

 }

@@ -1045,10 +1045,10 @@
 

     if(width != 0 && height != 0)

     {

-		sw::Rect sourceRect = {x, y, x + width, y + height};

+		sw::SliceRect sourceRect(x, y, x + width, y + height, 0);

 		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

         

-        copy(renderTarget, sourceRect, format, 0, 0, image[face][level]);

+        copy(renderTarget, sourceRect, format, 0, 0, 0, image[face][level]);

     }

 

 	renderTarget->release();

@@ -1075,7 +1075,7 @@
 

     GLsizei size = image[face][level]->getWidth();

 

-    if(xoffset + width > size || yoffset + height > size)

+    if(xoffset + width > size || yoffset + height > size || zoffset != 0)

     {

         return error(GL_INVALID_VALUE);

     }

@@ -1088,10 +1088,10 @@
         return error(GL_OUT_OF_MEMORY);

     }

 

-	sw::Rect sourceRect = {x, y, x + width, y + height};

+	sw::SliceRect sourceRect(x, y, x + width, y + height, 0);

 	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

 

-	copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, image[face][level]);

+	copy(renderTarget, sourceRect, image[face][level]->getFormat(), xoffset, yoffset, zoffset, image[face][level]);

 

 	renderTarget->release();

 }

@@ -1375,22 +1375,47 @@
 

 void Texture3D::copyImage(GLint level, GLenum format, GLint x, GLint y, GLint z, GLsizei width, GLsizei height, GLsizei depth, Framebuffer *source)

 {

-	UNIMPLEMENTED();

+	egl::Image *renderTarget = source->getRenderTarget();

+

+	if(!renderTarget)

+	{

+		ERR("Failed to retrieve the render target.");

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+	if(image[level])

+	{

+		image[level]->unbind(this);

+	}

+

+	image[level] = new Image(this, width, height, depth, format, GL_UNSIGNED_BYTE);

+

+	if(!image[level])

+	{

+		return error(GL_OUT_OF_MEMORY);

+	}

+

+	if(width != 0 && height != 0 && depth != 0)

+	{

+		sw::SliceRect sourceRect(x, y, x + width, y + height, z);

+		sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

+		for(GLint sliceZ = 0; sliceZ < depth; ++sliceZ, ++sourceRect.slice)

+		{

+			copy(renderTarget, sourceRect, format, 0, 0, sliceZ, image[level]);

+		}

+	}

+

+	renderTarget->release();

 }

 

 void Texture3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source)

 {

-	if(zoffset != 0)

-	{

-		UNIMPLEMENTED(); // FIXME: add support for copying into a layer other than layer 0

-	}

-

 	if(!image[level])

 	{

 		return error(GL_INVALID_OPERATION);

 	}

 

-	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight())

+	if(xoffset + width > image[level]->getWidth() || yoffset + height > image[level]->getHeight() || zoffset >= image[level]->getDepth())

 	{

 		return error(GL_INVALID_VALUE);

 	}

@@ -1403,10 +1428,10 @@
 		return error(GL_OUT_OF_MEMORY);

 	}

 

-	sw::Rect sourceRect = { x, y, x + width, y + height };

+	sw::SliceRect sourceRect = {x, y, x + width, y + height, 0};

 	sourceRect.clip(0, 0, source->getColorbuffer()->getWidth(), source->getColorbuffer()->getHeight());

 

-	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, image[level]);

+	copy(renderTarget, sourceRect, image[level]->getFormat(), xoffset, yoffset, zoffset, image[level]);

 

 	renderTarget->release();

 }

diff --git a/src/OpenGL/libGLESv2/Texture.h b/src/OpenGL/libGLESv2/Texture.h
index 806d94a..f078275 100644
--- a/src/OpenGL/libGLESv2/Texture.h
+++ b/src/OpenGL/libGLESv2/Texture.h
@@ -100,7 +100,7 @@
     void setCompressedImage(GLsizei imageSize, const void *pixels, egl::Image *image);

     void subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *pixels, egl::Image *image);

 

-	bool copy(egl::Image *source, const sw::Rect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, egl::Image *dest);

+	bool copy(egl::Image *source, const sw::SliceRect &sourceRect, GLenum destFormat, GLint xoffset, GLint yoffset, GLint zoffset, egl::Image *dest);

 

 	bool isMipmapFiltered() const;

 

@@ -138,7 +138,7 @@
     void subImage(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint unpackAlignment, const void *pixels);

     void subImageCompressed(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *pixels);

     void copyImage(GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

-	void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

+	virtual void copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, Framebuffer *source);

 

 	void setImage(egl::Image *image);

 

diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index abd0280..9cb3f10 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -4340,8 +4340,8 @@
 			texture = context->getTextureCubeMap();

 			break;

 		case GL_TEXTURE_EXTERNAL_OES:

-				texture = context->getTextureExternal();

-				break;

+			texture = context->getTextureExternal();

+			break;

 		default:

 			return error(GL_INVALID_ENUM);

 		}

diff --git a/src/Radiance/libRAD/Device.cpp b/src/Radiance/libRAD/Device.cpp
index 777cbd4..60f3b94 100644
--- a/src/Radiance/libRAD/Device.cpp
+++ b/src/Radiance/libRAD/Device.cpp
@@ -470,7 +470,7 @@
 		this->viewport = viewport;

 	}

 

-	bool Device::stretchRect(egl::Image *source, const sw::Rect *sourceRect, egl::Image *dest, const sw::Rect *destRect, bool filter)

+	bool Device::stretchRect(egl::Image *source, const sw::SliceRect *sourceRect, egl::Image *dest, const sw::SliceRect *destRect, bool filter)

 	{

 		if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))

 		{

@@ -483,8 +483,8 @@
 		int dWidth = dest->getExternalWidth();

 		int dHeight = dest->getExternalHeight();

 

-		Rect sRect;

-		Rect dRect;

+		SliceRect sRect;

+		SliceRect dRect;

 

 		if(sourceRect)

 		{

@@ -568,8 +568,8 @@
 		}

 		else if(!scaling && equalFormats)

 		{

-			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);

-			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);

+			unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sRect.slice, LOCK_READONLY, PUBLIC);

+			unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, LOCK_READWRITE, PUBLIC);

 			unsigned int sourcePitch = source->getInternalPitchB();

 			unsigned int destPitch = dest->getInternalPitchB();

 

diff --git a/src/Radiance/libRAD/Device.hpp b/src/Radiance/libRAD/Device.hpp
index 92a3a11..4dbe2e5 100644
--- a/src/Radiance/libRAD/Device.hpp
+++ b/src/Radiance/libRAD/Device.hpp
@@ -69,7 +69,7 @@
 		virtual void setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count);

 		virtual void setViewport(const Viewport &viewport);

 

-		virtual bool stretchRect(egl::Image *sourceSurface, const sw::Rect *sourceRect, egl::Image *destSurface, const sw::Rect *destRect, bool filter);

+		virtual bool stretchRect(egl::Image *sourceSurface, const sw::SliceRect *sourceRect, egl::Image *destSurface, const sw::SliceRect *destRect, bool filter);

 		virtual void finish();

 

 	private:

diff --git a/src/Radiance/libRAD/Texture.cpp b/src/Radiance/libRAD/Texture.cpp
index d84ff80..1a10072 100644
--- a/src/Radiance/libRAD/Texture.cpp
+++ b/src/Radiance/libRAD/Texture.cpp
@@ -273,8 +273,9 @@
 {

     Device *device = getDevice();

 	

-    sw::Rect destRect = {xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0)};

-    bool success = device->stretchRect(source, &sourceRect, dest, &destRect, false);

+    sw::SliceRect destRect(xoffset, yoffset, xoffset + (sourceRect.x1 - sourceRect.x0), yoffset + (sourceRect.y1 - sourceRect.y0), 0);

+    sw::SliceRect sourceSliceRect(sourceRect);

+    bool success = device->stretchRect(source, &sourceSliceRect, dest, &destRect, false);

 

     if(!success)

     {

diff --git a/src/Renderer/Blitter.cpp b/src/Renderer/Blitter.cpp
index 8817739..3bf1f39 100644
--- a/src/Renderer/Blitter.cpp
+++ b/src/Renderer/Blitter.cpp
@@ -26,15 +26,15 @@
 		delete blitCache;
 	}
 
-	void Blitter::blit(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter)
+	void Blitter::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
 	{
 		if(blitReactor(source, sRect, dest, dRect, filter))
 		{
 			return;
 		}
 
-		source->lockInternal(sRect.x0, sRect.y0, 0, sw::LOCK_READONLY, sw::PUBLIC);
-		dest->lockInternal(dRect.x0, dRect.y0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC);
+		source->lockInternal(sRect.x0, sRect.y0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
+		dest->lockInternal(dRect.x0, dRect.y0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 
 		float w = 1.0f / (dRect.x1 - dRect.x0) * (sRect.x1 - sRect.x0);
 		float h = 1.0f / (dRect.y1 - dRect.y0) * (sRect.y1 - sRect.y0);
@@ -115,7 +115,7 @@
 		return true;
 	}
 
-	bool Blitter::blitReactor(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter)
+	bool Blitter::blitReactor(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
 	{
 		BlitState state;
 
@@ -321,8 +321,8 @@
 
 		BlitData data;
 
-		data.source = source->lockInternal(0, 0, 0, sw::LOCK_READONLY, sw::PUBLIC);
-		data.dest = dest->lockInternal(0, 0, 0, sw::LOCK_WRITEONLY, sw::PUBLIC);
+		data.source = source->lockInternal(0, 0, sRect.slice, sw::LOCK_READONLY, sw::PUBLIC);
+		data.dest = dest->lockInternal(0, 0, dRect.slice, sw::LOCK_WRITEONLY, sw::PUBLIC);
 		data.sPitchB = source->getInternalPitchB();
 		data.dPitchB = dest->getInternalPitchB();
 
diff --git a/src/Renderer/Blitter.hpp b/src/Renderer/Blitter.hpp
index dc3bec9..d676a12 100644
--- a/src/Renderer/Blitter.hpp
+++ b/src/Renderer/Blitter.hpp
@@ -27,11 +27,11 @@
 

 		virtual ~Blitter();

 

-		void blit(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter);

+		void blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter);

 

 	private:

 		bool read(Float4 &color, Pointer<Byte> element, Format format);

-		bool blitReactor(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter);

+		bool blitReactor(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter);

 

 		struct BlitState

 		{

diff --git a/src/Renderer/Renderer.cpp b/src/Renderer/Renderer.cpp
index 7560900..8cc7651 100644
--- a/src/Renderer/Renderer.cpp
+++ b/src/Renderer/Renderer.cpp
@@ -186,7 +186,7 @@
 		delete swiftConfig;
 	}
 
-	void Renderer::blit(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter)
+	void Renderer::blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter)
 	{
 		blitter.blit(source, sRect, dest, dRect, filter);
 	}
diff --git a/src/Renderer/Renderer.hpp b/src/Renderer/Renderer.hpp
index fddd459..af1a950 100644
--- a/src/Renderer/Renderer.hpp
+++ b/src/Renderer/Renderer.hpp
@@ -270,7 +270,7 @@
 
 		virtual ~Renderer();
 
-		virtual void blit(Surface *source, const Rect &sRect, Surface *dest, const Rect &dRect, bool filter);
+		virtual void blit(Surface *source, const SliceRect &sRect, Surface *dest, const SliceRect &dRect, bool filter);
 		virtual void draw(DrawType drawType, unsigned int indexOffset, unsigned int count, bool update = true);
 
 		virtual void setIndexBuffer(Resource *indexBuffer);
diff --git a/src/Renderer/Surface.hpp b/src/Renderer/Surface.hpp
index 4eb481b..06f6d7c 100644
--- a/src/Renderer/Surface.hpp
+++ b/src/Renderer/Surface.hpp
@@ -22,6 +22,9 @@
 

 	struct Rect

 	{

+		Rect() {}

+		Rect(int x0i, int y0i, int x1i, int y1i) : x0(x0i), y0(y0i), x1(x1i), y1(y1i) {}

+

 		void clip(int minX, int minY, int maxX, int maxY);

 

 		int x0;   // Inclusive

@@ -30,6 +33,15 @@
 		int y1;   // Exclusive

 	};

 

+	struct SliceRect : public Rect

+	{

+		SliceRect() : slice(0) {}

+		SliceRect(const Rect& rect) : Rect(rect), slice(0) {}

+		SliceRect(const Rect& rect, int s) : Rect(rect), slice(s) {}

+		SliceRect(int x0, int y0, int x1, int y1, int s) : Rect(x0, y0, x1, y1), slice(s) {}

+		int slice;

+	};

+

 	enum Format : unsigned char

 	{

 		FORMAT_NULL,