Apply the Apache 2.0 license.
Change-Id: I4a7aeefedcd2d891093520d5a10ebefadcddb5be
Reviewed-on: https://swiftshader-review.googlesource.com/5320
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLES_CM/Device.cpp b/src/OpenGL/libGLES_CM/Device.cpp
index 65f29fc..7a7f022 100644
--- a/src/OpenGL/libGLES_CM/Device.cpp
+++ b/src/OpenGL/libGLES_CM/Device.cpp
@@ -1,608 +1,611 @@
-// SwiftShader Software Renderer
-//
-// Copyright(c) 2005-2013 TransGaming Inc.
-//
-// All rights reserved. No part of this software may be copied, distributed, transmitted,
-// transcribed, stored in a retrieval system, translated into any human or computer
-// language by any means, or disclosed to third parties without the explicit written
-// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
-// or implied, including but not limited to any patent rights, are granted to you.
-//
-
-#include "Device.hpp"
-
-#include "common/Image.hpp"
-#include "Texture.h"
-
-#include "Renderer/Renderer.hpp"
-#include "Renderer/Clipper.hpp"
-#include "Shader/PixelShader.hpp"
-#include "Shader/VertexShader.hpp"
-#include "Main/Config.hpp"
-#include "Main/FrameBuffer.hpp"
-#include "Common/Math.hpp"
-#include "Common/Configurator.hpp"
-#include "Common/Timer.hpp"
-#include "../common/debug.h"
-
-namespace es1
-{
- using namespace sw;
-
- Device::Device(Context *context) : Renderer(context, OpenGL, true), context(context)
- {
- renderTarget = nullptr;
- depthBuffer = nullptr;
- stencilBuffer = nullptr;
-
- setDepthBufferEnable(true);
- setFillMode(FILL_SOLID);
- setShadingMode(SHADING_GOURAUD);
- setDepthWriteEnable(true);
- setAlphaTestEnable(false);
- setSourceBlendFactor(BLEND_ONE);
- setDestBlendFactor(BLEND_ZERO);
- setCullMode(CULL_COUNTERCLOCKWISE);
- setDepthCompare(DEPTH_LESSEQUAL);
- setAlphaReference(0.0f);
- setAlphaCompare(ALPHA_ALWAYS);
- setAlphaBlendEnable(false);
- setFogEnable(false);
- setSpecularEnable(true);
- setLocalViewer(false);
- setFogColor(0);
- setPixelFogMode(FOG_NONE);
- setFogStart(0.0f);
- setFogEnd(1.0f);
- setFogDensity(1.0f);
- setRangeFogEnable(false);
- setStencilEnable(false);
- setStencilFailOperation(OPERATION_KEEP);
- setStencilZFailOperation(OPERATION_KEEP);
- setStencilPassOperation(OPERATION_KEEP);
- setStencilCompare(STENCIL_ALWAYS);
- setStencilReference(0);
- setStencilMask(0xFFFFFFFF);
- setStencilWriteMask(0xFFFFFFFF);
- setVertexFogMode(FOG_NONE);
- setClipFlags(0);
- setPointSize(1.0f);
- setPointSizeMin(0.125f);
- setPointSizeMax(8192.0f);
- setColorWriteMask(0, 0x0000000F);
- setBlendOperation(BLENDOP_ADD);
- scissorEnable = false;
- setSlopeDepthBias(0.0f);
- setTwoSidedStencil(false);
- setStencilFailOperationCCW(OPERATION_KEEP);
- setStencilZFailOperationCCW(OPERATION_KEEP);
- setStencilPassOperationCCW(OPERATION_KEEP);
- setStencilCompareCCW(STENCIL_ALWAYS);
- setColorWriteMask(1, 0x0000000F);
- setColorWriteMask(2, 0x0000000F);
- setColorWriteMask(3, 0x0000000F);
- setBlendConstant(0xFFFFFFFF);
- setWriteSRGB(false);
- setDepthBias(0.0f);
- setSeparateAlphaBlendEnable(false);
- setSourceBlendFactorAlpha(BLEND_ONE);
- setDestBlendFactorAlpha(BLEND_ZERO);
- setBlendOperationAlpha(BLENDOP_ADD);
- setPointSpriteEnable(true);
-
- for(int i = 0; i < 16; i++)
- {
- setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
- setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
- setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
- setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
- setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
- setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
- setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
- }
-
- for(int i = 0; i < 4; i++)
- {
- setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
- setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
- setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
- setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
- setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
- setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
- setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
- }
-
- for(int i = 0; i < 6; i++)
- {
- float plane[4] = {0, 0, 0, 0};
-
- setClipPlane(i, plane);
- }
- }
-
- Device::~Device()
- {
- if(renderTarget)
- {
- renderTarget->release();
- renderTarget = nullptr;
- }
-
- if(depthBuffer)
- {
- depthBuffer->release();
- depthBuffer = nullptr;
- }
-
- if(stencilBuffer)
- {
- stencilBuffer->release();
- stencilBuffer = nullptr;
- }
-
- delete context;
- }
-
- void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)
- {
- if(!renderTarget || !rgbaMask)
- {
- return;
- }
-
- float rgba[4];
- rgba[0] = red;
- rgba[1] = green;
- rgba[2] = blue;
- rgba[3] = alpha;
-
- sw::SliceRect clearRect = renderTarget->getRect();
-
- if(scissorEnable)
- {
- clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
- }
-
- clear(rgba, FORMAT_A32B32G32R32F, renderTarget, clearRect, rgbaMask);
- }
-
- void Device::clearDepth(float z)
- {
- if(!depthBuffer)
- {
- return;
- }
-
- z = clamp01(z);
- sw::SliceRect clearRect = depthBuffer->getRect();
-
- if(scissorEnable)
- {
- clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
- }
-
- depthBuffer->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
- }
-
- void Device::clearStencil(unsigned int stencil, unsigned int mask)
- {
- if(!stencilBuffer)
- {
- return;
- }
-
- sw::SliceRect clearRect = stencilBuffer->getRect();
-
- if(scissorEnable)
- {
- clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
- }
-
- stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
- }
-
- egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
- {
- if(height > OUTLINE_RESOLUTION)
- {
- ERR("Invalid parameters: %dx%d", width, height);
- return nullptr;
- }
-
- bool lockable = true;
-
- switch(format)
- {
- // case FORMAT_D15S1:
- case FORMAT_D24S8:
- case FORMAT_D24X8:
- // case FORMAT_D24X4S4:
- case FORMAT_D24FS8:
- case FORMAT_D32:
- case FORMAT_D16:
- lockable = false;
- break;
- // case FORMAT_S8_LOCKABLE:
- // case FORMAT_D16_LOCKABLE:
- case FORMAT_D32F_LOCKABLE:
- // case FORMAT_D32_LOCKABLE:
- case FORMAT_DF24S8:
- case FORMAT_DF16S8:
- lockable = true;
- break;
- default:
- UNREACHABLE(format);
- }
-
- egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
-
- if(!surface)
- {
- ERR("Out of memory");
- return nullptr;
- }
-
- return surface;
- }
-
- egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
- {
- if(height > OUTLINE_RESOLUTION)
- {
- ERR("Invalid parameters: %dx%d", width, height);
- return nullptr;
- }
-
- egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
-
- if(!surface)
- {
- ERR("Out of memory");
- return nullptr;
- }
-
- return surface;
- }
-
- void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
- {
- if(!bindResources() || !primitiveCount)
- {
- return;
- }
-
- draw(type, indexOffset, primitiveCount);
- }
-
- void Device::drawPrimitive(sw::DrawType type, unsigned int primitiveCount)
- {
- if(!bindResources() || !primitiveCount)
- {
- return;
- }
-
- setIndexBuffer(nullptr);
-
- draw(type, 0, primitiveCount);
- }
-
- void Device::setScissorEnable(bool enable)
- {
- scissorEnable = enable;
- }
-
- void Device::setRenderTarget(int index, egl::Image *renderTarget)
- {
- if(renderTarget)
- {
- renderTarget->addRef();
- }
-
- if(this->renderTarget)
- {
- this->renderTarget->release();
- }
-
- this->renderTarget = renderTarget;
-
- Renderer::setRenderTarget(index, renderTarget);
- }
-
- void Device::setDepthBuffer(egl::Image *depthBuffer)
- {
- if(this->depthBuffer == depthBuffer)
- {
- return;
- }
-
- if(depthBuffer)
- {
- depthBuffer->addRef();
- }
-
- if(this->depthBuffer)
- {
- this->depthBuffer->release();
- }
-
- this->depthBuffer = depthBuffer;
-
- Renderer::setDepthBuffer(depthBuffer);
- }
-
- void Device::setStencilBuffer(egl::Image *stencilBuffer)
- {
- if(this->stencilBuffer == stencilBuffer)
- {
- return;
- }
-
- if(stencilBuffer)
- {
- stencilBuffer->addRef();
- }
-
- if(this->stencilBuffer)
- {
- this->stencilBuffer->release();
- }
-
- this->stencilBuffer = stencilBuffer;
-
- Renderer::setStencilBuffer(stencilBuffer);
- }
-
- void Device::setScissorRect(const sw::Rect &rect)
- {
- scissorRect = rect;
- }
-
- void Device::setViewport(const Viewport &viewport)
- {
- this->viewport = viewport;
- }
-
- bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, bool filter)
- {
- if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))
- {
- ERR("Invalid parameters");
- return false;
- }
-
- int sWidth = source->getWidth();
- int sHeight = source->getHeight();
- int dWidth = dest->getWidth();
- int dHeight = dest->getHeight();
-
- SliceRect sRect;
- SliceRect dRect;
-
- if(sourceRect)
- {
- sRect = *sourceRect;
- }
- else
- {
- sRect.y0 = 0;
- sRect.x0 = 0;
- sRect.y1 = sHeight;
- sRect.x1 = sWidth;
- }
-
- if(destRect)
- {
- dRect = *destRect;
- }
- else
- {
- dRect.y0 = 0;
- dRect.x0 = 0;
- dRect.y1 = dHeight;
- dRect.x1 = dWidth;
- }
-
- bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
- bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
- bool depthStencil = egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat());
- bool alpha0xFF = false;
-
- if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
- (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
- {
- equalFormats = true;
- alpha0xFF = true;
- }
-
- if(depthStencil) // Copy entirely, internally // FIXME: Check
- {
- if(source->hasDepth())
- {
- 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->getWidth();
- unsigned int height = source->getHeight();
- unsigned int pitch = source->getInternalPitchB();
-
- for(unsigned int y = 0; y < height; y++)
- {
- memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
-
- sourceBuffer += pitch;
- destBuffer += pitch;
- }
-
- source->unlockInternal();
- dest->unlockInternal();
- }
-
- if(source->hasStencil())
- {
- sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
- sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
-
- unsigned int width = source->getWidth();
- unsigned int height = source->getHeight();
- unsigned int pitch = source->getStencilPitchB();
-
- for(unsigned int y = 0; y < height; y++)
- {
- memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
-
- sourceBuffer += pitch;
- destBuffer += pitch;
- }
-
- source->unlockStencil();
- dest->unlockStencil();
- }
- }
- else if(!scaling && equalFormats)
- {
- 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();
-
- unsigned int width = dRect.x1 - dRect.x0;
- unsigned int height = dRect.y1 - dRect.y0;
- unsigned int bytes = width * egl::Image::bytes(source->getInternalFormat());
-
- for(unsigned int y = 0; y < height; y++)
- {
- memcpy(destBytes, sourceBytes, bytes);
-
- if(alpha0xFF)
- {
- for(unsigned int x = 0; x < width; x++)
- {
- destBytes[4 * x + 3] = 0xFF;
- }
- }
-
- sourceBytes += sourcePitch;
- destBytes += destPitch;
- }
-
- source->unlockInternal();
- dest->unlockInternal();
- }
- else
- {
- blit(source, sRect, dest, dRect, scaling && filter);
- }
-
- return true;
- }
-
- bool Device::bindResources()
- {
- if(!bindViewport())
- {
- return false; // Zero-area target region
- }
-
- return true;
- }
-
- bool Device::bindViewport()
- {
- if(viewport.width <= 0 || viewport.height <= 0)
- {
- return false;
- }
-
- if(scissorEnable)
- {
- if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
- {
- return false;
- }
-
- sw::Rect scissor;
- scissor.x0 = scissorRect.x0;
- scissor.x1 = scissorRect.x1;
- scissor.y0 = scissorRect.y0;
- scissor.y1 = scissorRect.y1;
-
- setScissor(scissor);
- }
- else
- {
- sw::Rect scissor;
- scissor.x0 = viewport.x0;
- scissor.x1 = viewport.x0 + viewport.width;
- scissor.y0 = viewport.y0;
- scissor.y1 = viewport.y0 + viewport.height;
-
- if(renderTarget)
- {
- scissor.x0 = max(scissor.x0, 0);
- scissor.x1 = min(scissor.x1, renderTarget->getWidth());
- scissor.y0 = max(scissor.y0, 0);
- scissor.y1 = min(scissor.y1, renderTarget->getHeight());
- }
-
- if(depthBuffer)
- {
- scissor.x0 = max(scissor.x0, 0);
- scissor.x1 = min(scissor.x1, depthBuffer->getWidth());
- scissor.y0 = max(scissor.y0, 0);
- scissor.y1 = min(scissor.y1, depthBuffer->getHeight());
- }
-
- if(stencilBuffer)
- {
- scissor.x0 = max(scissor.x0, 0);
- scissor.x1 = min(scissor.x1, stencilBuffer->getWidth());
- scissor.y0 = max(scissor.y0, 0);
- scissor.y1 = min(scissor.y1, stencilBuffer->getHeight());
- }
-
- setScissor(scissor);
- }
-
- sw::Viewport view;
- view.x0 = (float)viewport.x0;
- view.y0 = (float)viewport.y0;
- view.width = (float)viewport.width;
- view.height = (float)viewport.height;
- view.minZ = viewport.minZ;
- view.maxZ = viewport.maxZ;
-
- Renderer::setViewport(view);
-
- return true;
- }
-
- bool Device::validRectangle(const sw::Rect *rect, sw::Surface *surface)
- {
- if(!rect)
- {
- return true;
- }
-
- if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
- {
- return false;
- }
-
- if(rect->x0 < 0 || rect->y0 < 0)
- {
- return false;
- }
-
- if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
- {
- return false;
- }
-
- return true;
- }
-
- void Device::finish()
- {
- synchronize();
- }
-}
+// 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 "Device.hpp"
+
+#include "common/Image.hpp"
+#include "Texture.h"
+
+#include "Renderer/Renderer.hpp"
+#include "Renderer/Clipper.hpp"
+#include "Shader/PixelShader.hpp"
+#include "Shader/VertexShader.hpp"
+#include "Main/Config.hpp"
+#include "Main/FrameBuffer.hpp"
+#include "Common/Math.hpp"
+#include "Common/Configurator.hpp"
+#include "Common/Timer.hpp"
+#include "../common/debug.h"
+
+namespace es1
+{
+ using namespace sw;
+
+ Device::Device(Context *context) : Renderer(context, OpenGL, true), context(context)
+ {
+ renderTarget = nullptr;
+ depthBuffer = nullptr;
+ stencilBuffer = nullptr;
+
+ setDepthBufferEnable(true);
+ setFillMode(FILL_SOLID);
+ setShadingMode(SHADING_GOURAUD);
+ setDepthWriteEnable(true);
+ setAlphaTestEnable(false);
+ setSourceBlendFactor(BLEND_ONE);
+ setDestBlendFactor(BLEND_ZERO);
+ setCullMode(CULL_COUNTERCLOCKWISE);
+ setDepthCompare(DEPTH_LESSEQUAL);
+ setAlphaReference(0.0f);
+ setAlphaCompare(ALPHA_ALWAYS);
+ setAlphaBlendEnable(false);
+ setFogEnable(false);
+ setSpecularEnable(true);
+ setLocalViewer(false);
+ setFogColor(0);
+ setPixelFogMode(FOG_NONE);
+ setFogStart(0.0f);
+ setFogEnd(1.0f);
+ setFogDensity(1.0f);
+ setRangeFogEnable(false);
+ setStencilEnable(false);
+ setStencilFailOperation(OPERATION_KEEP);
+ setStencilZFailOperation(OPERATION_KEEP);
+ setStencilPassOperation(OPERATION_KEEP);
+ setStencilCompare(STENCIL_ALWAYS);
+ setStencilReference(0);
+ setStencilMask(0xFFFFFFFF);
+ setStencilWriteMask(0xFFFFFFFF);
+ setVertexFogMode(FOG_NONE);
+ setClipFlags(0);
+ setPointSize(1.0f);
+ setPointSizeMin(0.125f);
+ setPointSizeMax(8192.0f);
+ setColorWriteMask(0, 0x0000000F);
+ setBlendOperation(BLENDOP_ADD);
+ scissorEnable = false;
+ setSlopeDepthBias(0.0f);
+ setTwoSidedStencil(false);
+ setStencilFailOperationCCW(OPERATION_KEEP);
+ setStencilZFailOperationCCW(OPERATION_KEEP);
+ setStencilPassOperationCCW(OPERATION_KEEP);
+ setStencilCompareCCW(STENCIL_ALWAYS);
+ setColorWriteMask(1, 0x0000000F);
+ setColorWriteMask(2, 0x0000000F);
+ setColorWriteMask(3, 0x0000000F);
+ setBlendConstant(0xFFFFFFFF);
+ setWriteSRGB(false);
+ setDepthBias(0.0f);
+ setSeparateAlphaBlendEnable(false);
+ setSourceBlendFactorAlpha(BLEND_ONE);
+ setDestBlendFactorAlpha(BLEND_ZERO);
+ setBlendOperationAlpha(BLENDOP_ADD);
+ setPointSpriteEnable(true);
+
+ for(int i = 0; i < 16; i++)
+ {
+ setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
+ setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
+ setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
+ setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
+ setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
+ }
+
+ for(int i = 0; i < 4; i++)
+ {
+ setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
+ setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
+ setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
+ setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
+ setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
+ }
+
+ for(int i = 0; i < 6; i++)
+ {
+ float plane[4] = {0, 0, 0, 0};
+
+ setClipPlane(i, plane);
+ }
+ }
+
+ Device::~Device()
+ {
+ if(renderTarget)
+ {
+ renderTarget->release();
+ renderTarget = nullptr;
+ }
+
+ if(depthBuffer)
+ {
+ depthBuffer->release();
+ depthBuffer = nullptr;
+ }
+
+ if(stencilBuffer)
+ {
+ stencilBuffer->release();
+ stencilBuffer = nullptr;
+ }
+
+ delete context;
+ }
+
+ void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask)
+ {
+ if(!renderTarget || !rgbaMask)
+ {
+ return;
+ }
+
+ float rgba[4];
+ rgba[0] = red;
+ rgba[1] = green;
+ rgba[2] = blue;
+ rgba[3] = alpha;
+
+ sw::SliceRect clearRect = renderTarget->getRect();
+
+ if(scissorEnable)
+ {
+ clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+ }
+
+ clear(rgba, FORMAT_A32B32G32R32F, renderTarget, clearRect, rgbaMask);
+ }
+
+ void Device::clearDepth(float z)
+ {
+ if(!depthBuffer)
+ {
+ return;
+ }
+
+ z = clamp01(z);
+ sw::SliceRect clearRect = depthBuffer->getRect();
+
+ if(scissorEnable)
+ {
+ clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+ }
+
+ depthBuffer->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
+ }
+
+ void Device::clearStencil(unsigned int stencil, unsigned int mask)
+ {
+ if(!stencilBuffer)
+ {
+ return;
+ }
+
+ sw::SliceRect clearRect = stencilBuffer->getRect();
+
+ if(scissorEnable)
+ {
+ clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1);
+ }
+
+ stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height());
+ }
+
+ egl::Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
+ {
+ if(height > OUTLINE_RESOLUTION)
+ {
+ ERR("Invalid parameters: %dx%d", width, height);
+ return nullptr;
+ }
+
+ bool lockable = true;
+
+ switch(format)
+ {
+ // case FORMAT_D15S1:
+ case FORMAT_D24S8:
+ case FORMAT_D24X8:
+ // case FORMAT_D24X4S4:
+ case FORMAT_D24FS8:
+ case FORMAT_D32:
+ case FORMAT_D16:
+ lockable = false;
+ break;
+ // case FORMAT_S8_LOCKABLE:
+ // case FORMAT_D16_LOCKABLE:
+ case FORMAT_D32F_LOCKABLE:
+ // case FORMAT_D32_LOCKABLE:
+ case FORMAT_DF24S8:
+ case FORMAT_DF16S8:
+ lockable = true;
+ break;
+ default:
+ UNREACHABLE(format);
+ }
+
+ egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
+
+ if(!surface)
+ {
+ ERR("Out of memory");
+ return nullptr;
+ }
+
+ return surface;
+ }
+
+ egl::Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
+ {
+ if(height > OUTLINE_RESOLUTION)
+ {
+ ERR("Invalid parameters: %dx%d", width, height);
+ return nullptr;
+ }
+
+ egl::Image *surface = new egl::Image(width, height, format, multiSampleDepth, lockable);
+
+ if(!surface)
+ {
+ ERR("Out of memory");
+ return nullptr;
+ }
+
+ return surface;
+ }
+
+ void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount)
+ {
+ if(!bindResources() || !primitiveCount)
+ {
+ return;
+ }
+
+ draw(type, indexOffset, primitiveCount);
+ }
+
+ void Device::drawPrimitive(sw::DrawType type, unsigned int primitiveCount)
+ {
+ if(!bindResources() || !primitiveCount)
+ {
+ return;
+ }
+
+ setIndexBuffer(nullptr);
+
+ draw(type, 0, primitiveCount);
+ }
+
+ void Device::setScissorEnable(bool enable)
+ {
+ scissorEnable = enable;
+ }
+
+ void Device::setRenderTarget(int index, egl::Image *renderTarget)
+ {
+ if(renderTarget)
+ {
+ renderTarget->addRef();
+ }
+
+ if(this->renderTarget)
+ {
+ this->renderTarget->release();
+ }
+
+ this->renderTarget = renderTarget;
+
+ Renderer::setRenderTarget(index, renderTarget);
+ }
+
+ void Device::setDepthBuffer(egl::Image *depthBuffer)
+ {
+ if(this->depthBuffer == depthBuffer)
+ {
+ return;
+ }
+
+ if(depthBuffer)
+ {
+ depthBuffer->addRef();
+ }
+
+ if(this->depthBuffer)
+ {
+ this->depthBuffer->release();
+ }
+
+ this->depthBuffer = depthBuffer;
+
+ Renderer::setDepthBuffer(depthBuffer);
+ }
+
+ void Device::setStencilBuffer(egl::Image *stencilBuffer)
+ {
+ if(this->stencilBuffer == stencilBuffer)
+ {
+ return;
+ }
+
+ if(stencilBuffer)
+ {
+ stencilBuffer->addRef();
+ }
+
+ if(this->stencilBuffer)
+ {
+ this->stencilBuffer->release();
+ }
+
+ this->stencilBuffer = stencilBuffer;
+
+ Renderer::setStencilBuffer(stencilBuffer);
+ }
+
+ void Device::setScissorRect(const sw::Rect &rect)
+ {
+ scissorRect = rect;
+ }
+
+ void Device::setViewport(const Viewport &viewport)
+ {
+ this->viewport = viewport;
+ }
+
+ bool Device::stretchRect(sw::Surface *source, const sw::SliceRect *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, bool filter)
+ {
+ if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))
+ {
+ ERR("Invalid parameters");
+ return false;
+ }
+
+ int sWidth = source->getWidth();
+ int sHeight = source->getHeight();
+ int dWidth = dest->getWidth();
+ int dHeight = dest->getHeight();
+
+ SliceRect sRect;
+ SliceRect dRect;
+
+ if(sourceRect)
+ {
+ sRect = *sourceRect;
+ }
+ else
+ {
+ sRect.y0 = 0;
+ sRect.x0 = 0;
+ sRect.y1 = sHeight;
+ sRect.x1 = sWidth;
+ }
+
+ if(destRect)
+ {
+ dRect = *destRect;
+ }
+ else
+ {
+ dRect.y0 = 0;
+ dRect.x0 = 0;
+ dRect.y1 = dHeight;
+ dRect.x1 = dWidth;
+ }
+
+ bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
+ bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
+ bool depthStencil = egl::Image::isDepth(source->getInternalFormat()) || egl::Image::isStencil(source->getInternalFormat());
+ bool alpha0xFF = false;
+
+ if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
+ (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
+ {
+ equalFormats = true;
+ alpha0xFF = true;
+ }
+
+ if(depthStencil) // Copy entirely, internally // FIXME: Check
+ {
+ if(source->hasDepth())
+ {
+ 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->getWidth();
+ unsigned int height = source->getHeight();
+ unsigned int pitch = source->getInternalPitchB();
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
+
+ sourceBuffer += pitch;
+ destBuffer += pitch;
+ }
+
+ source->unlockInternal();
+ dest->unlockInternal();
+ }
+
+ if(source->hasStencil())
+ {
+ sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
+ sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
+
+ unsigned int width = source->getWidth();
+ unsigned int height = source->getHeight();
+ unsigned int pitch = source->getStencilPitchB();
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
+
+ sourceBuffer += pitch;
+ destBuffer += pitch;
+ }
+
+ source->unlockStencil();
+ dest->unlockStencil();
+ }
+ }
+ else if(!scaling && equalFormats)
+ {
+ 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();
+
+ unsigned int width = dRect.x1 - dRect.x0;
+ unsigned int height = dRect.y1 - dRect.y0;
+ unsigned int bytes = width * egl::Image::bytes(source->getInternalFormat());
+
+ for(unsigned int y = 0; y < height; y++)
+ {
+ memcpy(destBytes, sourceBytes, bytes);
+
+ if(alpha0xFF)
+ {
+ for(unsigned int x = 0; x < width; x++)
+ {
+ destBytes[4 * x + 3] = 0xFF;
+ }
+ }
+
+ sourceBytes += sourcePitch;
+ destBytes += destPitch;
+ }
+
+ source->unlockInternal();
+ dest->unlockInternal();
+ }
+ else
+ {
+ blit(source, sRect, dest, dRect, scaling && filter);
+ }
+
+ return true;
+ }
+
+ bool Device::bindResources()
+ {
+ if(!bindViewport())
+ {
+ return false; // Zero-area target region
+ }
+
+ return true;
+ }
+
+ bool Device::bindViewport()
+ {
+ if(viewport.width <= 0 || viewport.height <= 0)
+ {
+ return false;
+ }
+
+ if(scissorEnable)
+ {
+ if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
+ {
+ return false;
+ }
+
+ sw::Rect scissor;
+ scissor.x0 = scissorRect.x0;
+ scissor.x1 = scissorRect.x1;
+ scissor.y0 = scissorRect.y0;
+ scissor.y1 = scissorRect.y1;
+
+ setScissor(scissor);
+ }
+ else
+ {
+ sw::Rect scissor;
+ scissor.x0 = viewport.x0;
+ scissor.x1 = viewport.x0 + viewport.width;
+ scissor.y0 = viewport.y0;
+ scissor.y1 = viewport.y0 + viewport.height;
+
+ if(renderTarget)
+ {
+ scissor.x0 = max(scissor.x0, 0);
+ scissor.x1 = min(scissor.x1, renderTarget->getWidth());
+ scissor.y0 = max(scissor.y0, 0);
+ scissor.y1 = min(scissor.y1, renderTarget->getHeight());
+ }
+
+ if(depthBuffer)
+ {
+ scissor.x0 = max(scissor.x0, 0);
+ scissor.x1 = min(scissor.x1, depthBuffer->getWidth());
+ scissor.y0 = max(scissor.y0, 0);
+ scissor.y1 = min(scissor.y1, depthBuffer->getHeight());
+ }
+
+ if(stencilBuffer)
+ {
+ scissor.x0 = max(scissor.x0, 0);
+ scissor.x1 = min(scissor.x1, stencilBuffer->getWidth());
+ scissor.y0 = max(scissor.y0, 0);
+ scissor.y1 = min(scissor.y1, stencilBuffer->getHeight());
+ }
+
+ setScissor(scissor);
+ }
+
+ sw::Viewport view;
+ view.x0 = (float)viewport.x0;
+ view.y0 = (float)viewport.y0;
+ view.width = (float)viewport.width;
+ view.height = (float)viewport.height;
+ view.minZ = viewport.minZ;
+ view.maxZ = viewport.maxZ;
+
+ Renderer::setViewport(view);
+
+ return true;
+ }
+
+ bool Device::validRectangle(const sw::Rect *rect, sw::Surface *surface)
+ {
+ if(!rect)
+ {
+ return true;
+ }
+
+ if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
+ {
+ return false;
+ }
+
+ if(rect->x0 < 0 || rect->y0 < 0)
+ {
+ return false;
+ }
+
+ if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ void Device::finish()
+ {
+ synchronize();
+ }
+}