John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 1 | // SwiftShader Software Renderer
|
| 2 | //
|
| 3 | // Copyright(c) 2005-2013 TransGaming Inc.
|
| 4 | //
|
| 5 | // All rights reserved. No part of this software may be copied, distributed, transmitted,
|
| 6 | // transcribed, stored in a retrieval system, translated into any human or computer
|
| 7 | // language by any means, or disclosed to third parties without the explicit written
|
| 8 | // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
|
| 9 | // or implied, including but not limited to any patent rights, are granted to you.
|
| 10 | //
|
| 11 |
|
| 12 | #include "Device.hpp"
|
| 13 |
|
| 14 | #include "Image.hpp"
|
| 15 | #include "Texture.h"
|
| 16 |
|
| 17 | #include "Renderer/Renderer.hpp"
|
| 18 | #include "Renderer/Clipper.hpp"
|
| 19 | #include "Shader/PixelShader.hpp"
|
| 20 | #include "Shader/VertexShader.hpp"
|
| 21 | #include "Main/Config.hpp"
|
| 22 | #include "Main/FrameBuffer.hpp"
|
| 23 | #include "Common/Math.hpp"
|
| 24 | #include "Common/Configurator.hpp"
|
| 25 | #include "Common/Timer.hpp"
|
| 26 | #include "../common/debug.h"
|
| 27 |
|
| 28 | bool localShaderConstants = false;
|
| 29 |
|
Nicolas Capens | 14ee762 | 2014-10-28 23:48:41 -0400 | [diff] [blame] | 30 | namespace es2
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 31 | {
|
| 32 | using namespace sw;
|
| 33 |
|
| 34 | Device::Device(Context *context) : Renderer(context, true, true, true, true, true), context(context)
|
| 35 | {
|
| 36 | depthStencil = 0;
|
| 37 | renderTarget = 0;
|
| 38 |
|
| 39 | setDepthBufferEnable(true);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 40 | setFillMode(FILL_SOLID);
|
| 41 | setShadingMode(SHADING_GOURAUD);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 42 | setDepthWriteEnable(true);
|
| 43 | setAlphaTestEnable(false);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 44 | setSourceBlendFactor(BLEND_ONE);
|
| 45 | setDestBlendFactor(BLEND_ZERO);
|
| 46 | setCullMode(CULL_COUNTERCLOCKWISE);
|
| 47 | setDepthCompare(DEPTH_LESSEQUAL);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 48 | setAlphaReference(0);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 49 | setAlphaCompare(ALPHA_ALWAYS);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 50 | setAlphaBlendEnable(false);
|
| 51 | setFogEnable(false);
|
| 52 | setSpecularEnable(false);
|
| 53 | setFogColor(0);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 54 | setPixelFogMode(FOG_NONE);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 55 | setFogStart(0.0f);
|
| 56 | setFogEnd(1.0f);
|
| 57 | setFogDensity(1.0f);
|
| 58 | setRangeFogEnable(false);
|
| 59 | setStencilEnable(false);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 60 | setStencilFailOperation(OPERATION_KEEP);
|
| 61 | setStencilZFailOperation(OPERATION_KEEP);
|
| 62 | setStencilPassOperation(OPERATION_KEEP);
|
| 63 | setStencilCompare(STENCIL_ALWAYS);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 64 | setStencilReference(0);
|
| 65 | setStencilMask(0xFFFFFFFF);
|
| 66 | setStencilWriteMask(0xFFFFFFFF);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 67 | setVertexFogMode(FOG_NONE);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 68 | setClipFlags(0);
|
| 69 | setPointSize(1.0f);
|
| 70 | setPointSizeMin(0.125f);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 71 | setPointSizeMax(8192.0f);
|
| 72 | setColorWriteMask(0, 0x0000000F);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 73 | setBlendOperation(BLENDOP_ADD);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 74 | scissorEnable = false;
|
| 75 | setSlopeDepthBias(0.0f);
|
| 76 | setTwoSidedStencil(false);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 77 | setStencilFailOperationCCW(OPERATION_KEEP);
|
| 78 | setStencilZFailOperationCCW(OPERATION_KEEP);
|
| 79 | setStencilPassOperationCCW(OPERATION_KEEP);
|
| 80 | setStencilCompareCCW(STENCIL_ALWAYS);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 81 | setColorWriteMask(1, 0x0000000F);
|
| 82 | setColorWriteMask(2, 0x0000000F);
|
| 83 | setColorWriteMask(3, 0x0000000F);
|
| 84 | setBlendConstant(0xFFFFFFFF);
|
| 85 | setWriteSRGB(false);
|
| 86 | setDepthBias(0.0f);
|
| 87 | setSeparateAlphaBlendEnable(false);
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 88 | setSourceBlendFactorAlpha(BLEND_ONE);
|
| 89 | setDestBlendFactorAlpha(BLEND_ZERO);
|
| 90 | setBlendOperationAlpha(BLENDOP_ADD);
|
Nicolas Capens | c78445c | 2014-10-27 17:29:04 -0400 | [diff] [blame] | 91 | setPointSpriteEnable(true);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 92 |
|
| 93 | for(int i = 0; i < 16; i++)
|
| 94 | {
|
| 95 | setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
|
| 96 | setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
|
| 97 | setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
|
| 98 | setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
|
| 99 | setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
|
| 100 | setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
|
| 101 | setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
|
| 102 | }
|
| 103 |
|
| 104 | for(int i = 0; i < 4; i++)
|
| 105 | {
|
| 106 | setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
|
| 107 | setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
|
| 108 | setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
|
| 109 | setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
|
| 110 | setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
|
| 111 | setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
|
| 112 | setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
|
| 113 | }
|
| 114 |
|
| 115 | for(int i = 0; i < 6; i++)
|
| 116 | {
|
| 117 | float plane[4] = {0, 0, 0, 0};
|
| 118 |
|
| 119 | setClipPlane(i, plane);
|
| 120 | }
|
| 121 |
|
| 122 | pixelShader = 0;
|
| 123 | vertexShader = 0;
|
| 124 |
|
| 125 | pixelShaderDirty = true;
|
| 126 | pixelShaderConstantsFDirty = 0;
|
| 127 | vertexShaderDirty = true;
|
| 128 | vertexShaderConstantsFDirty = 0;
|
| 129 |
|
| 130 | for(int i = 0; i < 224; i++)
|
| 131 | {
|
| 132 | float zero[4] = {0, 0, 0, 0};
|
| 133 |
|
| 134 | setPixelShaderConstantF(i, zero, 1);
|
| 135 | }
|
| 136 |
|
| 137 | for(int i = 0; i < 256; i++)
|
| 138 | {
|
| 139 | float zero[4] = {0, 0, 0, 0};
|
| 140 |
|
| 141 | setVertexShaderConstantF(i, zero, 1);
|
| 142 | }
|
| 143 | }
|
| 144 |
|
| 145 | Device::~Device()
|
| 146 | {
|
| 147 | if(depthStencil)
|
| 148 | {
|
| 149 | depthStencil->release();
|
| 150 | depthStencil = 0;
|
| 151 | }
|
| 152 |
|
| 153 | if(renderTarget)
|
| 154 | {
|
| 155 | renderTarget->release();
|
| 156 | renderTarget = 0;
|
| 157 | }
|
| 158 |
|
| 159 | delete context;
|
| 160 | }
|
| 161 |
|
| 162 | void Device::clearColor(unsigned int color, unsigned int rgbaMask)
|
| 163 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 164 | if(!renderTarget)
|
| 165 | {
|
| 166 | return;
|
| 167 | }
|
| 168 |
|
| 169 | int x0 = 0;
|
| 170 | int y0 = 0;
|
| 171 | int width = renderTarget->getExternalWidth();
|
| 172 | int height = renderTarget->getExternalHeight();
|
| 173 |
|
| 174 | if(scissorEnable) // Clamp against scissor rectangle
|
| 175 | {
|
| 176 | if(x0 < scissorRect.x0) x0 = scissorRect.x0;
|
| 177 | if(y0 < scissorRect.y0) y0 = scissorRect.y0;
|
| 178 | if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
|
| 179 | if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
|
| 180 | }
|
| 181 |
|
| 182 | renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);
|
| 183 | }
|
| 184 |
|
| 185 | void Device::clearDepth(float z)
|
| 186 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 187 | if(!depthStencil)
|
| 188 | {
|
| 189 | return;
|
| 190 | }
|
| 191 |
|
| 192 | if(z > 1) z = 1;
|
| 193 | if(z < 0) z = 0;
|
| 194 |
|
| 195 | int x0 = 0;
|
| 196 | int y0 = 0;
|
| 197 | int width = depthStencil->getExternalWidth();
|
| 198 | int height = depthStencil->getExternalHeight();
|
| 199 |
|
| 200 | if(scissorEnable) // Clamp against scissor rectangle
|
| 201 | {
|
| 202 | if(x0 < scissorRect.x0) x0 = scissorRect.x0;
|
| 203 | if(y0 < scissorRect.y0) y0 = scissorRect.y0;
|
| 204 | if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
|
| 205 | if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
|
| 206 | }
|
| 207 |
|
| 208 | depthStencil->clearDepthBuffer(z, x0, y0, width, height);
|
| 209 | }
|
| 210 |
|
| 211 | void Device::clearStencil(unsigned int stencil, unsigned int mask)
|
| 212 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 213 | if(!depthStencil)
|
| 214 | {
|
| 215 | return;
|
| 216 | }
|
| 217 |
|
| 218 | int x0 = 0;
|
| 219 | int y0 = 0;
|
| 220 | int width = depthStencil->getExternalWidth();
|
| 221 | int height = depthStencil->getExternalHeight();
|
| 222 |
|
| 223 | if(scissorEnable) // Clamp against scissor rectangle
|
| 224 | {
|
| 225 | if(x0 < scissorRect.x0) x0 = scissorRect.x0;
|
| 226 | if(y0 < scissorRect.y0) y0 = scissorRect.y0;
|
| 227 | if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
|
| 228 | if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
|
| 229 | }
|
| 230 |
|
| 231 | depthStencil->clearStencilBuffer(stencil, mask, x0, y0, width, height);
|
| 232 | }
|
| 233 |
|
| 234 | Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
|
| 235 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 236 | if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
|
| 237 | {
|
| 238 | ERR("Invalid parameters");
|
| 239 | return 0;
|
| 240 | }
|
| 241 |
|
| 242 | bool lockable = true;
|
| 243 |
|
| 244 | switch(format)
|
| 245 | {
|
| 246 | // case FORMAT_D15S1:
|
| 247 | case FORMAT_D24S8:
|
| 248 | case FORMAT_D24X8:
|
| 249 | // case FORMAT_D24X4S4:
|
| 250 | case FORMAT_D24FS8:
|
| 251 | case FORMAT_D32:
|
| 252 | case FORMAT_D16:
|
| 253 | lockable = false;
|
| 254 | break;
|
| 255 | // case FORMAT_S8_LOCKABLE:
|
| 256 | // case FORMAT_D16_LOCKABLE:
|
| 257 | case FORMAT_D32F_LOCKABLE:
|
| 258 | // case FORMAT_D32_LOCKABLE:
|
| 259 | case FORMAT_DF24S8:
|
| 260 | case FORMAT_DF16S8:
|
| 261 | lockable = true;
|
| 262 | break;
|
| 263 | default:
|
| 264 | UNREACHABLE();
|
| 265 | }
|
| 266 |
|
Nicolas Capens | 16ea3c8 | 2014-10-28 12:07:06 -0400 | [diff] [blame] | 267 | Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 268 |
|
| 269 | if(!surface)
|
| 270 | {
|
| 271 | ERR("Out of memory");
|
| 272 | return 0;
|
| 273 | }
|
| 274 |
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 275 | return surface;
|
| 276 | }
|
| 277 |
|
| 278 | Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
|
| 279 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 280 | if(height > OUTLINE_RESOLUTION)
|
| 281 | {
|
| 282 | ERR("Invalid parameters");
|
| 283 | return 0;
|
| 284 | }
|
| 285 |
|
Nicolas Capens | 16ea3c8 | 2014-10-28 12:07:06 -0400 | [diff] [blame] | 286 | Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 287 |
|
| 288 | if(!surface)
|
| 289 | {
|
| 290 | ERR("Out of memory");
|
| 291 | return 0;
|
| 292 | }
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 293 |
|
| 294 | return surface;
|
| 295 | }
|
| 296 |
|
| 297 | void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)
|
| 298 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 299 | if(!bindResources() || !primitiveCount)
|
| 300 | {
|
| 301 | return;
|
| 302 | }
|
| 303 |
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 304 | DrawType drawType;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 305 |
|
| 306 | if(indexSize == 4)
|
| 307 | {
|
| 308 | switch(type)
|
| 309 | {
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 310 | case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST32; break;
|
| 311 | case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST32; break;
|
| 312 | case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP32; break;
|
| 313 | case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP32; break;
|
| 314 | case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST32; break;
|
| 315 | case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break;
|
| 316 | case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN32; break;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 317 | default: UNREACHABLE();
|
| 318 | }
|
| 319 | }
|
| 320 | else if(indexSize == 2)
|
| 321 | {
|
| 322 | switch(type)
|
| 323 | {
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 324 | case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST16; break;
|
| 325 | case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST16; break;
|
| 326 | case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP16; break;
|
| 327 | case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP16; break;
|
| 328 | case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST16; break;
|
| 329 | case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break;
|
| 330 | case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN16; break;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 331 | default: UNREACHABLE();
|
| 332 | }
|
| 333 | }
|
| 334 | else if(indexSize == 1)
|
| 335 | {
|
| 336 | switch(type)
|
| 337 | {
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 338 | case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST8; break;
|
| 339 | case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST8; break;
|
| 340 | case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP8; break;
|
| 341 | case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP8; break;
|
| 342 | case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST8; break;
|
| 343 | case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP8; break;
|
| 344 | case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN8; break;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 345 | default: UNREACHABLE();
|
| 346 | }
|
| 347 | }
|
| 348 | else UNREACHABLE();
|
| 349 |
|
| 350 | draw(drawType, indexOffset, primitiveCount);
|
| 351 | }
|
| 352 |
|
| 353 | void Device::drawPrimitive(PrimitiveType primitiveType, unsigned int primitiveCount)
|
| 354 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 355 | if(!bindResources() || !primitiveCount)
|
| 356 | {
|
| 357 | return;
|
| 358 | }
|
| 359 |
|
| 360 | setIndexBuffer(0);
|
| 361 |
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 362 | DrawType drawType;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 363 |
|
| 364 | switch(primitiveType)
|
| 365 | {
|
Nicolas Capens | a0f4be8 | 2014-10-22 14:35:30 -0400 | [diff] [blame] | 366 | case DRAW_POINTLIST: drawType = sw::DRAW_POINTLIST; break;
|
| 367 | case DRAW_LINELIST: drawType = sw::DRAW_LINELIST; break;
|
| 368 | case DRAW_LINESTRIP: drawType = sw::DRAW_LINESTRIP; break;
|
| 369 | case DRAW_LINELOOP: drawType = sw::DRAW_LINELOOP; break;
|
| 370 | case DRAW_TRIANGLELIST: drawType = sw::DRAW_TRIANGLELIST; break;
|
| 371 | case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break;
|
| 372 | case DRAW_TRIANGLEFAN: drawType = sw::DRAW_TRIANGLEFAN; break;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 373 | default: UNREACHABLE();
|
| 374 | }
|
| 375 |
|
| 376 | draw(drawType, 0, primitiveCount);
|
| 377 | }
|
| 378 |
|
Nicolas Capens | ead7ac5 | 2014-10-27 23:56:02 -0400 | [diff] [blame] | 379 | void Device::setDepthStencilSurface(egl::Image *depthStencil)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 380 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 381 | if(this->depthStencil == depthStencil)
|
| 382 | {
|
| 383 | return;
|
| 384 | }
|
| 385 |
|
| 386 | if(depthStencil)
|
| 387 | {
|
| 388 | depthStencil->addRef();
|
| 389 | }
|
| 390 |
|
| 391 | if(this->depthStencil)
|
| 392 | {
|
| 393 | this->depthStencil->release();
|
| 394 | }
|
| 395 |
|
| 396 | this->depthStencil = depthStencil;
|
| 397 |
|
| 398 | setDepthStencil(depthStencil);
|
| 399 | }
|
| 400 |
|
| 401 | void Device::setPixelShader(PixelShader *pixelShader)
|
| 402 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 403 | this->pixelShader = pixelShader;
|
| 404 | pixelShaderDirty = true;
|
| 405 | }
|
| 406 |
|
| 407 | void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
|
| 408 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 409 | for(unsigned int i = 0; i < count && startRegister + i < 224; i++)
|
| 410 | {
|
| 411 | pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
|
| 412 | pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
|
| 413 | pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
|
| 414 | pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
|
| 415 | }
|
| 416 |
|
| 417 | pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty);
|
| 418 | pixelShaderDirty = true; // Reload DEF constants
|
| 419 | }
|
| 420 |
|
| 421 | void Device::setScissorEnable(bool enable)
|
| 422 | {
|
| 423 | scissorEnable = enable;
|
| 424 | }
|
| 425 |
|
Nicolas Capens | ead7ac5 | 2014-10-27 23:56:02 -0400 | [diff] [blame] | 426 | void Device::setRenderTarget(egl::Image *renderTarget)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 427 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 428 | if(renderTarget)
|
| 429 | {
|
| 430 | renderTarget->addRef();
|
| 431 | }
|
| 432 |
|
| 433 | if(this->renderTarget)
|
| 434 | {
|
| 435 | this->renderTarget->release();
|
| 436 | }
|
| 437 |
|
| 438 | this->renderTarget = renderTarget;
|
| 439 |
|
| 440 | Renderer::setRenderTarget(0, renderTarget);
|
| 441 | }
|
| 442 |
|
| 443 | void Device::setScissorRect(const sw::Rect &rect)
|
| 444 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 445 | scissorRect = rect;
|
| 446 | }
|
| 447 |
|
| 448 | void Device::setVertexShader(VertexShader *vertexShader)
|
| 449 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 450 | this->vertexShader = vertexShader;
|
| 451 | vertexShaderDirty = true;
|
| 452 | }
|
| 453 |
|
| 454 | void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
|
| 455 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 456 | for(unsigned int i = 0; i < count && startRegister + i < 256; i++)
|
| 457 | {
|
| 458 | vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
|
| 459 | vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
|
| 460 | vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
|
| 461 | vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
|
| 462 | }
|
| 463 |
|
| 464 | vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty);
|
| 465 | vertexShaderDirty = true; // Reload DEF constants
|
| 466 | }
|
| 467 |
|
| 468 | void Device::setViewport(const Viewport &viewport)
|
| 469 | {
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 470 | this->viewport = viewport;
|
| 471 | }
|
| 472 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 473 | void Device::copyBuffer(sw::byte *sourceBuffer, sw::byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY)
|
| 474 | {
|
| 475 | unsigned int widthB = width * bytes;
|
| 476 | unsigned int widthMaxB = widthB - 1;
|
| 477 |
|
| 478 | if(flipX)
|
| 479 | {
|
| 480 | if(flipY)
|
| 481 | {
|
| 482 | sourceBuffer += (height - 1) * sourcePitch;
|
| 483 | for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch)
|
| 484 | {
|
| 485 | for(unsigned int x = 0; x < widthB; ++x)
|
| 486 | {
|
| 487 | destBuffer[x] = sourceBuffer[widthMaxB - x];
|
| 488 | }
|
| 489 | }
|
| 490 | }
|
| 491 | else
|
| 492 | {
|
| 493 | for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch)
|
| 494 | {
|
| 495 | for(unsigned int x = 0; x < widthB; ++x)
|
| 496 | {
|
| 497 | destBuffer[x] = sourceBuffer[widthMaxB - x];
|
| 498 | }
|
| 499 | }
|
| 500 | }
|
| 501 | }
|
| 502 | else
|
| 503 | {
|
| 504 | if(flipY)
|
| 505 | {
|
| 506 | sourceBuffer += (height - 1) * sourcePitch;
|
| 507 | for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch)
|
| 508 | {
|
| 509 | memcpy(destBuffer, sourceBuffer, widthB);
|
| 510 | }
|
| 511 | }
|
| 512 | else
|
| 513 | {
|
| 514 | for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch)
|
| 515 | {
|
| 516 | memcpy(destBuffer, sourceBuffer, widthB);
|
| 517 | }
|
| 518 | }
|
| 519 | }
|
| 520 | }
|
| 521 |
|
Alexis Hetu | f7be67f | 2015-02-11 16:11:07 -0500 | [diff] [blame] | 522 | bool Device::stretchRect(egl::Image *source, const sw::SliceRect *sourceRect, egl::Image *dest, const sw::SliceRect *destRect, bool filter)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 523 | {
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 524 | if(!source || !dest)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 525 | {
|
| 526 | ERR("Invalid parameters");
|
| 527 | return false;
|
| 528 | }
|
| 529 |
|
| 530 | int sWidth = source->getExternalWidth();
|
| 531 | int sHeight = source->getExternalHeight();
|
| 532 | int dWidth = dest->getExternalWidth();
|
| 533 | int dHeight = dest->getExternalHeight();
|
| 534 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 535 | bool flipX = false;
|
| 536 | bool flipY = false;
|
| 537 | if(sourceRect && destRect)
|
| 538 | {
|
| 539 | flipX = (sourceRect->x0 < sourceRect->x1) ^ (destRect->x0 < destRect->x1);
|
| 540 | flipY = (sourceRect->y0 < sourceRect->y1) ^ (destRect->y0 < destRect->y1);
|
| 541 | }
|
| 542 | else if(sourceRect)
|
| 543 | {
|
| 544 | flipX = (sourceRect->x0 > sourceRect->x1);
|
| 545 | flipY = (sourceRect->y0 > sourceRect->y1);
|
| 546 | }
|
| 547 | else if(destRect)
|
| 548 | {
|
| 549 | flipX = (destRect->x0 > destRect->x1);
|
| 550 | flipY = (destRect->y0 > destRect->y1);
|
| 551 | }
|
| 552 |
|
Alexis Hetu | f7be67f | 2015-02-11 16:11:07 -0500 | [diff] [blame] | 553 | SliceRect sRect;
|
| 554 | SliceRect dRect;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 555 |
|
| 556 | if(sourceRect)
|
| 557 | {
|
| 558 | sRect = *sourceRect;
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 559 |
|
| 560 | if(sRect.x0 > sRect.x1)
|
| 561 | {
|
| 562 | swap(sRect.x0, sRect.x1);
|
| 563 | }
|
| 564 |
|
| 565 | if(sRect.y0 > sRect.y1)
|
| 566 | {
|
| 567 | swap(sRect.y0, sRect.y1);
|
| 568 | }
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 569 | }
|
| 570 | else
|
| 571 | {
|
| 572 | sRect.y0 = 0;
|
| 573 | sRect.x0 = 0;
|
| 574 | sRect.y1 = sHeight;
|
| 575 | sRect.x1 = sWidth;
|
| 576 | }
|
| 577 |
|
| 578 | if(destRect)
|
| 579 | {
|
| 580 | dRect = *destRect;
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 581 |
|
| 582 | if(dRect.x0 > dRect.x1)
|
| 583 | {
|
| 584 | swap(dRect.x0, dRect.x1);
|
| 585 | }
|
| 586 |
|
| 587 | if(dRect.y0 > dRect.y1)
|
| 588 | {
|
| 589 | swap(dRect.y0, dRect.y1);
|
| 590 | }
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 591 | }
|
| 592 | else
|
| 593 | {
|
| 594 | dRect.y0 = 0;
|
| 595 | dRect.x0 = 0;
|
| 596 | dRect.y1 = dHeight;
|
| 597 | dRect.x1 = dWidth;
|
| 598 | }
|
| 599 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 600 | if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest))
|
| 601 | {
|
| 602 | ERR("Invalid parameters");
|
| 603 | return false;
|
| 604 | }
|
| 605 |
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 606 | bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
|
| 607 | bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
|
| 608 | bool depthStencil = Image::isDepth(source->getInternalFormat()) || Image::isStencil(source->getInternalFormat());
|
| 609 | bool alpha0xFF = false;
|
| 610 |
|
| 611 | if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
|
| 612 | (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
|
| 613 | {
|
| 614 | equalFormats = true;
|
| 615 | alpha0xFF = true;
|
| 616 | }
|
| 617 |
|
| 618 | if(depthStencil) // Copy entirely, internally // FIXME: Check
|
| 619 | {
|
| 620 | if(source->hasDepth())
|
| 621 | {
|
Alexis Hetu | f7be67f | 2015-02-11 16:11:07 -0500 | [diff] [blame] | 622 | sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, sourceRect->slice, LOCK_READONLY, PUBLIC);
|
| 623 | sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, destRect->slice, LOCK_DISCARD, PUBLIC);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 624 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 625 | copyBuffer(sourceBuffer, destBuffer, source->getInternalWidth(), source->getInternalHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), Image::bytes(source->getInternalFormat()), flipX, flipY);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 626 |
|
| 627 | source->unlockInternal();
|
| 628 | dest->unlockInternal();
|
| 629 | }
|
| 630 |
|
| 631 | if(source->hasStencil())
|
| 632 | {
|
| 633 | sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
|
| 634 | sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
|
| 635 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 636 | copyBuffer(sourceBuffer, destBuffer, source->getInternalWidth(), source->getInternalHeight(), source->getInternalPitchB(), dest->getInternalPitchB(), Image::bytes(source->getInternalFormat()), flipX, flipY);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 637 |
|
| 638 | source->unlockStencil();
|
| 639 | dest->unlockStencil();
|
| 640 | }
|
| 641 | }
|
| 642 | else if(!scaling && equalFormats)
|
| 643 | {
|
Alexis Hetu | f7be67f | 2015-02-11 16:11:07 -0500 | [diff] [blame] | 644 | unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC);
|
| 645 | unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, LOCK_READWRITE, PUBLIC);
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 646 | unsigned int sourcePitch = source->getInternalPitchB();
|
| 647 | unsigned int destPitch = dest->getInternalPitchB();
|
| 648 |
|
| 649 | unsigned int width = dRect.x1 - dRect.x0;
|
| 650 | unsigned int height = dRect.y1 - dRect.y0;
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 651 |
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 652 | copyBuffer(sourceBytes, destBytes, width, height, sourcePitch, destPitch, Image::bytes(source->getInternalFormat()), flipX, flipY);
|
| 653 |
|
| 654 | if(alpha0xFF)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 655 | {
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 656 | for(unsigned int y = 0; y < height; ++y, destBytes += destPitch)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 657 | {
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 658 | for(unsigned int x = 0; x < width; ++x)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 659 | {
|
| 660 | destBytes[4 * x + 3] = 0xFF;
|
| 661 | }
|
| 662 | }
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 663 | }
|
| 664 |
|
| 665 | source->unlockInternal();
|
| 666 | dest->unlockInternal();
|
| 667 | }
|
| 668 | else
|
| 669 | {
|
Alexis Hetu | e9233fb | 2015-02-11 10:31:58 -0500 | [diff] [blame^] | 670 | if(flipX)
|
| 671 | {
|
| 672 | swap(dRect.x0, dRect.x1);
|
| 673 | }
|
| 674 | if(flipY)
|
| 675 | {
|
| 676 | swap(dRect.y0, dRect.y1);
|
| 677 | }
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 678 | blit(source, sRect, dest, dRect, scaling && filter);
|
| 679 | }
|
| 680 |
|
| 681 | return true;
|
| 682 | }
|
| 683 |
|
| 684 | bool Device::bindResources()
|
| 685 | {
|
| 686 | if(!bindViewport())
|
| 687 | {
|
| 688 | return false; // Zero-area target region
|
| 689 | }
|
| 690 |
|
| 691 | bindShaderConstants();
|
| 692 |
|
| 693 | return true;
|
| 694 | }
|
| 695 |
|
| 696 | void Device::bindShaderConstants()
|
| 697 | {
|
| 698 | if(pixelShaderDirty)
|
| 699 | {
|
| 700 | if(pixelShader)
|
| 701 | {
|
| 702 | if(pixelShaderConstantsFDirty)
|
| 703 | {
|
| 704 | Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty);
|
| 705 | }
|
| 706 |
|
| 707 | Renderer::setPixelShader(pixelShader); // Loads shader constants set with DEF
|
| 708 | pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
|
| 709 | }
|
| 710 | else
|
| 711 | {
|
| 712 | setPixelShader(0);
|
| 713 | }
|
| 714 |
|
| 715 | pixelShaderDirty = false;
|
| 716 | }
|
| 717 |
|
| 718 | if(vertexShaderDirty)
|
| 719 | {
|
| 720 | if(vertexShader)
|
| 721 | {
|
| 722 | if(vertexShaderConstantsFDirty)
|
| 723 | {
|
| 724 | Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty);
|
| 725 | }
|
| 726 |
|
| 727 | Renderer::setVertexShader(vertexShader); // Loads shader constants set with DEF
|
| 728 | vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
|
| 729 | }
|
| 730 | else
|
| 731 | {
|
| 732 | setVertexShader(0);
|
| 733 | }
|
| 734 |
|
| 735 | vertexShaderDirty = false;
|
| 736 | }
|
| 737 | }
|
| 738 |
|
| 739 | bool Device::bindViewport()
|
| 740 | {
|
| 741 | if(viewport.width <= 0 || viewport.height <= 0)
|
| 742 | {
|
| 743 | return false;
|
| 744 | }
|
| 745 |
|
| 746 | if(scissorEnable)
|
| 747 | {
|
| 748 | if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
|
| 749 | {
|
| 750 | return false;
|
| 751 | }
|
| 752 |
|
| 753 | sw::Rect scissor;
|
| 754 | scissor.x0 = scissorRect.x0;
|
| 755 | scissor.x1 = scissorRect.x1;
|
| 756 | scissor.y0 = scissorRect.y0;
|
| 757 | scissor.y1 = scissorRect.y1;
|
| 758 |
|
| 759 | setScissor(scissor);
|
| 760 | }
|
| 761 | else
|
| 762 | {
|
| 763 | sw::Rect scissor;
|
| 764 | scissor.x0 = viewport.x0;
|
| 765 | scissor.x1 = viewport.x0 + viewport.width;
|
| 766 | scissor.y0 = viewport.y0;
|
| 767 | scissor.y1 = viewport.y0 + viewport.height;
|
| 768 |
|
| 769 | if(renderTarget)
|
| 770 | {
|
| 771 | scissor.x0 = max(scissor.x0, 0);
|
| 772 | scissor.x1 = min(scissor.x1, renderTarget->getExternalWidth());
|
| 773 | scissor.y0 = max(scissor.y0, 0);
|
| 774 | scissor.y1 = min(scissor.y1, renderTarget->getExternalHeight());
|
| 775 | }
|
| 776 |
|
| 777 | if(depthStencil)
|
| 778 | {
|
| 779 | scissor.x0 = max(scissor.x0, 0);
|
| 780 | scissor.x1 = min(scissor.x1, depthStencil->getExternalWidth());
|
| 781 | scissor.y0 = max(scissor.y0, 0);
|
| 782 | scissor.y1 = min(scissor.y1, depthStencil->getExternalHeight());
|
| 783 | }
|
| 784 |
|
| 785 | setScissor(scissor);
|
| 786 | }
|
| 787 |
|
| 788 | sw::Viewport view;
|
| 789 | view.x0 = (float)viewport.x0;
|
| 790 | view.y0 = (float)viewport.y0;
|
| 791 | view.width = (float)viewport.width;
|
| 792 | view.height = (float)viewport.height;
|
| 793 | view.minZ = viewport.minZ;
|
| 794 | view.maxZ = viewport.maxZ;
|
| 795 |
|
| 796 | Renderer::setViewport(view);
|
| 797 |
|
| 798 | return true;
|
| 799 | }
|
| 800 |
|
Nicolas Capens | ead7ac5 | 2014-10-27 23:56:02 -0400 | [diff] [blame] | 801 | bool Device::validRectangle(const sw::Rect *rect, egl::Image *surface)
|
John Bauman | 66b8ab2 | 2014-05-06 15:57:45 -0400 | [diff] [blame] | 802 | {
|
| 803 | if(!rect)
|
| 804 | {
|
| 805 | return true;
|
| 806 | }
|
| 807 |
|
| 808 | if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
|
| 809 | {
|
| 810 | return false;
|
| 811 | }
|
| 812 |
|
| 813 | if(rect->x0 < 0 || rect->y0 < 0)
|
| 814 | {
|
| 815 | return false;
|
| 816 | }
|
| 817 |
|
| 818 | if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
|
| 819 | {
|
| 820 | return false;
|
| 821 | }
|
| 822 |
|
| 823 | return true;
|
| 824 | }
|
| 825 |
|
| 826 | void Device::finish()
|
| 827 | {
|
| 828 | synchronize();
|
| 829 | }
|
| 830 | }
|