// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "Image.hpp" #include "Texture.h" #include "utilities.h" #include "../common/debug.h" #include "Common/Thread.hpp" #define _GDI32_ #include <windows.h> #include <GL/GL.h> #include <GL/glext.h> namespace gl { static sw::Resource *getParentResource(Texture *texture) { if(texture) { return texture->getResource(); } return nullptr; } Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, GLenum format, GLenum type) : sw::Surface(getParentResource(parentTexture), width, height, 1, 0, 1, selectInternalFormat(format, type), true, true) , parentTexture(parentTexture), width(width), height(height), format(format), type(type) , internalFormat(selectInternalFormat(format, type)), multiSampleDepth(1) { referenceCount = 1; } Image::Image(Texture *parentTexture, GLsizei width, GLsizei height, sw::Format internalFormat, int multiSampleDepth, bool lockable, bool renderTarget) : sw::Surface(getParentResource(parentTexture), width, height, 1, 0, multiSampleDepth, internalFormat, lockable, renderTarget) , parentTexture(parentTexture), width(width), height(height), format(0 /*GL_NONE*/), type(0 /*GL_NONE*/), internalFormat(internalFormat), multiSampleDepth(multiSampleDepth) { referenceCount = 1; } Image::~Image() { ASSERT(referenceCount == 0); } void *Image::lock(unsigned int left, unsigned int top, sw::Lock lock) { return lockExternal(left, top, 0, lock, sw::PUBLIC); } unsigned int Image::getPitch() const { return getExternalPitchB(); } void Image::unlock() { unlockExternal(); } void *Image::lockInternal(int x, int y, int z, sw::Lock lock, sw::Accessor client) { return Surface::lockInternal(x, y, z, lock, client); } void Image::unlockInternal() { Surface::unlockInternal(); } int Image::getWidth() { return width; } int Image::getHeight() { return height; } GLenum Image::getFormat() { return format; } GLenum Image::getType() { return type; } sw::Format Image::getInternalFormat() { return internalFormat; } int Image::getMultiSampleDepth() { return multiSampleDepth; } void Image::addRef() { if(parentTexture) { return parentTexture->addRef(); } sw::atomicIncrement(&referenceCount); } void Image::release() { if(parentTexture) { return parentTexture->release(); } if(referenceCount > 0) { sw::atomicDecrement(&referenceCount); } if(referenceCount == 0) { delete this; } } void Image::unbind() { parentTexture = nullptr; release(); } sw::Format Image::selectInternalFormat(GLenum format, GLenum type) { if(type == GL_NONE && format == GL_NONE) { return sw::FORMAT_NULL; } else if(format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) { return sw::FORMAT_DXT1; } else if(format == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) { return sw::FORMAT_DXT3; } else if(format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) { return sw::FORMAT_DXT5; } else if(type == GL_FLOAT) { return sw::FORMAT_A32B32G32R32F; } else if(type == GL_HALF_FLOAT) { return sw::FORMAT_A16B16G16R16F; } else if(type == GL_UNSIGNED_BYTE) { if(format == GL_LUMINANCE) { return sw::FORMAT_L8; } else if(format == GL_LUMINANCE_ALPHA) { return sw::FORMAT_A8L8; } else if(format == GL_RGBA || format == GL_BGRA_EXT) { return sw::FORMAT_A8R8G8B8; } else if(format == GL_RGB) { return sw::FORMAT_X8R8G8B8; } else if(format == GL_ALPHA) { return sw::FORMAT_A8; } else UNREACHABLE(format); } else if(type == GL_UNSIGNED_SHORT || type == GL_UNSIGNED_INT) { if(format == GL_DEPTH_COMPONENT) { return sw::FORMAT_D32FS8_TEXTURE; } else UNREACHABLE(format); } else if(type == GL_UNSIGNED_INT_24_8_EXT) { if(format == GL_DEPTH_STENCIL_EXT) { return sw::FORMAT_D32FS8_TEXTURE; } else UNREACHABLE(format); } else if(type == GL_UNSIGNED_SHORT_4_4_4_4) { return sw::FORMAT_A8R8G8B8; } else if(type == GL_UNSIGNED_SHORT_5_5_5_1) { return sw::FORMAT_A8R8G8B8; } else if(type == GL_UNSIGNED_SHORT_5_6_5) { return sw::FORMAT_R5G6B5; } else if(type == GL_UNSIGNED_INT_8_8_8_8_REV) { return sw::FORMAT_A8R8G8B8; } else UNREACHABLE(type); return sw::FORMAT_A8R8G8B8; } void Image::loadImageData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLint unpackAlignment, const void *input) { GLsizei inputPitch = ComputePitch(width, format, type, unpackAlignment); void *buffer = lock(0, 0, sw::LOCK_WRITEONLY); if(buffer) { switch(type) { case GL_UNSIGNED_BYTE: case GL_UNSIGNED_INT_8_8_8_8_REV: switch(format) { case GL_ALPHA: loadAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE: loadLuminanceImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE_ALPHA: loadLuminanceAlphaImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGB: loadRGBUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGBA: loadRGBAUByteImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_BGRA_EXT: loadBGRAImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_5_6_5: switch(format) { case GL_RGB: loadRGB565ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_4_4_4_4: switch(format) { case GL_RGBA: loadRGBA4444ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT_5_5_5_1: switch(format) { case GL_RGBA: loadRGBA5551ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_FLOAT: switch(format) { // float textures are converted to RGBA, not BGRA case GL_ALPHA: loadAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE: loadLuminanceFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE_ALPHA: loadLuminanceAlphaFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGB: loadRGBFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGBA: loadRGBAFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_HALF_FLOAT: switch(format) { // float textures are converted to RGBA, not BGRA case GL_ALPHA: loadAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE: loadLuminanceHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_LUMINANCE_ALPHA: loadLuminanceAlphaHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGB: loadRGBHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_RGBA: loadRGBAHalfFloatImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(format); } break; case GL_UNSIGNED_SHORT: loadD16ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_UNSIGNED_INT: loadD32ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; case GL_UNSIGNED_INT_24_8_EXT: loadD24S8ImageData(xoffset, yoffset, width, height, inputPitch, input, buffer); break; default: UNREACHABLE(type); } } unlock(); } void Image::loadAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset; memcpy(dest, source, width); } } void Image::loadAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16); for(int x = 0; x < width; x++) { dest[4 * x + 0] = 0; dest[4 * x + 1] = 0; dest[4 * x + 2] = 0; dest[4 * x + 3] = source[x]; } } } void Image::loadAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8); for(int x = 0; x < width; x++) { dest[4 * x + 0] = 0; dest[4 * x + 1] = 0; dest[4 * x + 2] = 0; dest[4 * x + 3] = source[x]; } } } void Image::loadLuminanceImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset; memcpy(dest, source, width); } } void Image::loadLuminanceFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[x]; dest[4 * x + 1] = source[x]; dest[4 * x + 2] = source[x]; dest[4 * x + 3] = 1.0f; } } } void Image::loadLuminanceHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[x]; dest[4 * x + 1] = source[x]; dest[4 * x + 2] = source[x]; dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 } } } void Image::loadLuminanceAlphaImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 2; memcpy(dest, source, width * 2); } } void Image::loadLuminanceAlphaFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[2*x+0]; dest[4 * x + 1] = source[2*x+0]; dest[4 * x + 2] = source[2*x+0]; dest[4 * x + 3] = source[2*x+1]; } } } void Image::loadLuminanceAlphaHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[2*x+0]; dest[4 * x + 1] = source[2*x+0]; dest[4 * x + 2] = source[2*x+0]; dest[4 * x + 3] = source[2*x+1]; } } } void Image::loadRGBUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4; for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[x * 3 + 2]; dest[4 * x + 1] = source[x * 3 + 1]; dest[4 * x + 2] = source[x * 3 + 0]; dest[4 * x + 3] = 0xFF; } } } void Image::loadRGB565ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 2; memcpy(dest, source, width * 2); } } void Image::loadRGBFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[x * 3 + 0]; dest[4 * x + 1] = source[x * 3 + 1]; dest[4 * x + 2] = source[x * 3 + 2]; dest[4 * x + 3] = 1.0f; } } } void Image::loadRGBHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned short *dest = reinterpret_cast<unsigned short*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8); for(int x = 0; x < width; x++) { dest[4 * x + 0] = source[x * 3 + 0]; dest[4 * x + 1] = source[x * 3 + 1]; dest[4 * x + 2] = source[x * 3 + 2]; dest[4 * x + 3] = 0x3C00; // SEEEEEMMMMMMMMMM, S = 0, E = 15, M = 0: 16bit flpt representation of 1 } } } void Image::loadRGBAUByteImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned int *dest = reinterpret_cast<unsigned int*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4); for(int x = 0; x < width; x++) { unsigned int rgba = source[x]; dest[x] = (rgba & 0xFF00FF00) | ((rgba << 16) & 0x00FF0000) | ((rgba >> 16) & 0x000000FF); } } } void Image::loadRGBA4444ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4; for(int x = 0; x < width; x++) { unsigned short rgba = source[x]; dest[4 * x + 0] = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); dest[4 * x + 1] = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); dest[4 * x + 2] = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); dest[4 * x + 3] = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); } } } void Image::loadRGBA5551ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4; for(int x = 0; x < width; x++) { unsigned short rgba = source[x]; dest[4 * x + 0] = ((rgba & 0x003E) << 2) | ((rgba & 0x003E) >> 3); dest[4 * x + 1] = ((rgba & 0x07C0) >> 3) | ((rgba & 0x07C0) >> 8); dest[4 * x + 2] = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); dest[4 * x + 3] = (rgba & 0x0001) ? 0xFF : 0; } } } void Image::loadRGBAFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const float *source = reinterpret_cast<const float*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 16); memcpy(dest, source, width * 16); } } void Image::loadRGBAHalfFloatImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 8; memcpy(dest, source, width * 8); } } void Image::loadBGRAImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned char *source = static_cast<const unsigned char*>(input) + y * inputPitch; unsigned char *dest = static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4; memcpy(dest, source, width*4); } } void Image::loadD16ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned short *source = reinterpret_cast<const unsigned short*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4); for(int x = 0; x < width; x++) { dest[x] = (float)source[x] / 0xFFFF; } } } void Image::loadD32ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) const { for(int y = 0; y < height; y++) { const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4); for(int x = 0; x < width; x++) { dest[x] = (float)source[x] / 0xFFFFFFFF; } } } void Image::loadD24S8ImageData(GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, int inputPitch, const void *input, void *buffer) { for(int y = 0; y < height; y++) { const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); float *dest = reinterpret_cast<float*>(static_cast<unsigned char*>(buffer) + (y + yoffset) * getPitch() + xoffset * 4); for(int x = 0; x < width; x++) { dest[x] = (float)(source[x] & 0xFFFFFF00) / 0xFFFFFF00; } } unsigned char *stencil = reinterpret_cast<unsigned char*>(lockStencil(0, 0, 0, sw::PUBLIC)); if(stencil) { for(int y = 0; y < height; y++) { const unsigned int *source = reinterpret_cast<const unsigned int*>(static_cast<const unsigned char*>(input) + y * inputPitch); unsigned char *dest = static_cast<unsigned char*>(stencil) + (y + yoffset) * getStencilPitchB() + xoffset; for(int x = 0; x < width; x++) { dest[x] = static_cast<unsigned char>(source[x] & 0x000000FF); // FIXME: Quad layout } } unlockStencil(); } } void Image::loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLsizei imageSize, const void *pixels) { int inputPitch = ComputeCompressedPitch(width, format); int rows = imageSize / inputPitch; void *buffer = lock(xoffset, yoffset, sw::LOCK_WRITEONLY); if(buffer) { for(int i = 0; i < rows; i++) { memcpy((void*)((GLbyte*)buffer + i * getPitch()), (void*)((GLbyte*)pixels + i * inputPitch), inputPitch); } } unlock(); } }