1 // SwiftShader Software Renderer
\r
3 // Copyright(c) 2005-2013 TransGaming Inc.
\r
5 // All rights reserved. No part of this software may be copied, distributed, transmitted,
\r
6 // transcribed, stored in a retrieval system, translated into any human or computer
\r
7 // language by any means, or disclosed to third parties without the explicit written
\r
8 // agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
\r
9 // or implied, including but not limited to any patent rights, are granted to you.
\r
12 #include "Device.hpp"
\r
14 #include "Image.hpp"
\r
15 #include "Texture.h"
\r
17 #include "Renderer/Renderer.hpp"
\r
18 #include "Renderer/Clipper.hpp"
\r
19 #include "Shader/PixelShader.hpp"
\r
20 #include "Shader/VertexShader.hpp"
\r
21 #include "Main/Config.hpp"
\r
22 #include "Main/FrameBuffer.hpp"
\r
23 #include "Common/Math.hpp"
\r
24 #include "Common/Configurator.hpp"
\r
25 #include "Common/Timer.hpp"
\r
26 #include "../common/debug.h"
\r
28 bool localShaderConstants = false;
\r
34 Device::Device(Context *context) : Renderer(context, true, true, true, true, true), context(context)
\r
39 setDepthBufferEnable(true);
\r
40 setFillMode(FILL_SOLID);
\r
41 setShadingMode(SHADING_GOURAUD);
\r
42 setDepthWriteEnable(true);
\r
43 setAlphaTestEnable(false);
\r
44 setSourceBlendFactor(BLEND_ONE);
\r
45 setDestBlendFactor(BLEND_ZERO);
\r
46 setCullMode(CULL_COUNTERCLOCKWISE);
\r
47 setDepthCompare(DEPTH_LESSEQUAL);
\r
48 setAlphaReference(0);
\r
49 setAlphaCompare(ALPHA_ALWAYS);
\r
50 setAlphaBlendEnable(false);
\r
51 setFogEnable(false);
\r
52 setSpecularEnable(false);
\r
54 setPixelFogMode(FOG_NONE);
\r
57 setFogDensity(1.0f);
\r
58 setRangeFogEnable(false);
\r
59 setStencilEnable(false);
\r
60 setStencilFailOperation(OPERATION_KEEP);
\r
61 setStencilZFailOperation(OPERATION_KEEP);
\r
62 setStencilPassOperation(OPERATION_KEEP);
\r
63 setStencilCompare(STENCIL_ALWAYS);
\r
64 setStencilReference(0);
\r
65 setStencilMask(0xFFFFFFFF);
\r
66 setStencilWriteMask(0xFFFFFFFF);
\r
67 setVertexFogMode(FOG_NONE);
\r
70 setPointSizeMin(0.125f);
\r
71 setPointSpriteEnable(false);
\r
72 setPointSizeMax(8192.0f);
\r
73 setColorWriteMask(0, 0x0000000F);
\r
74 setBlendOperation(BLENDOP_ADD);
\r
75 scissorEnable = false;
\r
76 setSlopeDepthBias(0.0f);
\r
77 setTwoSidedStencil(false);
\r
78 setStencilFailOperationCCW(OPERATION_KEEP);
\r
79 setStencilZFailOperationCCW(OPERATION_KEEP);
\r
80 setStencilPassOperationCCW(OPERATION_KEEP);
\r
81 setStencilCompareCCW(STENCIL_ALWAYS);
\r
82 setColorWriteMask(1, 0x0000000F);
\r
83 setColorWriteMask(2, 0x0000000F);
\r
84 setColorWriteMask(3, 0x0000000F);
\r
85 setBlendConstant(0xFFFFFFFF);
\r
86 setWriteSRGB(false);
\r
88 setSeparateAlphaBlendEnable(false);
\r
89 setSourceBlendFactorAlpha(BLEND_ONE);
\r
90 setDestBlendFactorAlpha(BLEND_ZERO);
\r
91 setBlendOperationAlpha(BLENDOP_ADD);
\r
92 setPointSpriteEnable(true);
\r
94 for(int i = 0; i < 16; i++)
\r
96 setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
\r
97 setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
\r
98 setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP);
\r
99 setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000);
\r
100 setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT);
\r
101 setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE);
\r
102 setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f);
\r
105 for(int i = 0; i < 4; i++)
\r
107 setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
\r
108 setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
\r
109 setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP);
\r
110 setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000);
\r
111 setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT);
\r
112 setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE);
\r
113 setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f);
\r
116 for(int i = 0; i < 6; i++)
\r
118 float plane[4] = {0, 0, 0, 0};
\r
120 setClipPlane(i, plane);
\r
126 pixelShaderDirty = true;
\r
127 pixelShaderConstantsFDirty = 0;
\r
128 vertexShaderDirty = true;
\r
129 vertexShaderConstantsFDirty = 0;
\r
131 for(int i = 0; i < 224; i++)
\r
133 float zero[4] = {0, 0, 0, 0};
\r
135 setPixelShaderConstantF(i, zero, 1);
\r
138 for(int i = 0; i < 256; i++)
\r
140 float zero[4] = {0, 0, 0, 0};
\r
142 setVertexShaderConstantF(i, zero, 1);
\r
150 depthStencil->release();
\r
156 renderTarget->release();
\r
163 void Device::clearColor(unsigned int color, unsigned int rgbaMask)
\r
172 int width = renderTarget->getExternalWidth();
\r
173 int height = renderTarget->getExternalHeight();
\r
175 if(scissorEnable) // Clamp against scissor rectangle
\r
177 if(x0 < scissorRect.x0) x0 = scissorRect.x0;
\r
178 if(y0 < scissorRect.y0) y0 = scissorRect.y0;
\r
179 if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
\r
180 if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
\r
183 renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);
\r
186 void Device::clearDepth(float z)
\r
198 int width = depthStencil->getExternalWidth();
\r
199 int height = depthStencil->getExternalHeight();
\r
201 if(scissorEnable) // Clamp against scissor rectangle
\r
203 if(x0 < scissorRect.x0) x0 = scissorRect.x0;
\r
204 if(y0 < scissorRect.y0) y0 = scissorRect.y0;
\r
205 if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
\r
206 if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
\r
209 depthStencil->clearDepthBuffer(z, x0, y0, width, height);
\r
212 void Device::clearStencil(unsigned int stencil, unsigned int mask)
\r
221 int width = depthStencil->getExternalWidth();
\r
222 int height = depthStencil->getExternalHeight();
\r
224 if(scissorEnable) // Clamp against scissor rectangle
\r
226 if(x0 < scissorRect.x0) x0 = scissorRect.x0;
\r
227 if(y0 < scissorRect.y0) y0 = scissorRect.y0;
\r
228 if(width > scissorRect.x1 - scissorRect.x0) width = scissorRect.x1 - scissorRect.x0;
\r
229 if(height > scissorRect.y1 - scissorRect.y0) height = scissorRect.y1 - scissorRect.y0;
\r
232 depthStencil->clearStencilBuffer(stencil, mask, x0, y0, width, height);
\r
235 Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)
\r
237 if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)
\r
239 ERR("Invalid parameters");
\r
243 bool lockable = true;
\r
247 // case FORMAT_D15S1:
\r
250 // case FORMAT_D24X4S4:
\r
251 case FORMAT_D24FS8:
\r
256 // case FORMAT_S8_LOCKABLE:
\r
257 // case FORMAT_D16_LOCKABLE:
\r
258 case FORMAT_D32F_LOCKABLE:
\r
259 // case FORMAT_D32_LOCKABLE:
\r
260 case FORMAT_DF24S8:
\r
261 case FORMAT_DF16S8:
\r
268 Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);
\r
272 ERR("Out of memory");
\r
279 Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)
\r
281 if(height > OUTLINE_RESOLUTION)
\r
283 ERR("Invalid parameters");
\r
287 Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);
\r
291 ERR("Out of memory");
\r
298 void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)
\r
300 if(!bindResources() || !primitiveCount)
\r
311 case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST32; break;
\r
312 case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST32; break;
\r
313 case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP32; break;
\r
314 case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP32; break;
\r
315 case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST32; break;
\r
316 case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP32; break;
\r
317 case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN32; break;
\r
318 default: UNREACHABLE();
\r
321 else if(indexSize == 2)
\r
325 case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST16; break;
\r
326 case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST16; break;
\r
327 case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP16; break;
\r
328 case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP16; break;
\r
329 case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST16; break;
\r
330 case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP16; break;
\r
331 case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN16; break;
\r
332 default: UNREACHABLE();
\r
335 else if(indexSize == 1)
\r
339 case DRAW_POINTLIST: drawType = sw::DRAW_INDEXEDPOINTLIST8; break;
\r
340 case DRAW_LINELIST: drawType = sw::DRAW_INDEXEDLINELIST8; break;
\r
341 case DRAW_LINESTRIP: drawType = sw::DRAW_INDEXEDLINESTRIP8; break;
\r
342 case DRAW_LINELOOP: drawType = sw::DRAW_INDEXEDLINELOOP8; break;
\r
343 case DRAW_TRIANGLELIST: drawType = sw::DRAW_INDEXEDTRIANGLELIST8; break;
\r
344 case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_INDEXEDTRIANGLESTRIP8; break;
\r
345 case DRAW_TRIANGLEFAN: drawType = sw::DRAW_INDEXEDTRIANGLEFAN8; break;
\r
346 default: UNREACHABLE();
\r
349 else UNREACHABLE();
\r
351 draw(drawType, indexOffset, primitiveCount);
\r
354 void Device::drawPrimitive(PrimitiveType primitiveType, unsigned int primitiveCount)
\r
356 if(!bindResources() || !primitiveCount)
\r
365 switch(primitiveType)
\r
367 case DRAW_POINTLIST: drawType = sw::DRAW_POINTLIST; break;
\r
368 case DRAW_LINELIST: drawType = sw::DRAW_LINELIST; break;
\r
369 case DRAW_LINESTRIP: drawType = sw::DRAW_LINESTRIP; break;
\r
370 case DRAW_LINELOOP: drawType = sw::DRAW_LINELOOP; break;
\r
371 case DRAW_TRIANGLELIST: drawType = sw::DRAW_TRIANGLELIST; break;
\r
372 case DRAW_TRIANGLESTRIP: drawType = sw::DRAW_TRIANGLESTRIP; break;
\r
373 case DRAW_TRIANGLEFAN: drawType = sw::DRAW_TRIANGLEFAN; break;
\r
374 default: UNREACHABLE();
\r
377 draw(drawType, 0, primitiveCount);
\r
380 void Device::setDepthStencilSurface(egl::Image *depthStencil)
\r
382 if(this->depthStencil == depthStencil)
\r
389 depthStencil->addRef();
\r
392 if(this->depthStencil)
\r
394 this->depthStencil->release();
\r
397 this->depthStencil = depthStencil;
\r
399 setDepthStencil(depthStencil);
\r
402 void Device::setPixelShader(PixelShader *pixelShader)
\r
404 this->pixelShader = pixelShader;
\r
405 pixelShaderDirty = true;
\r
408 void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
\r
410 for(unsigned int i = 0; i < count && startRegister + i < 224; i++)
\r
412 pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
\r
413 pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
\r
414 pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
\r
415 pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
\r
418 pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty);
\r
419 pixelShaderDirty = true; // Reload DEF constants
\r
422 void Device::setScissorEnable(bool enable)
\r
424 scissorEnable = enable;
\r
427 void Device::setRenderTarget(egl::Image *renderTarget)
\r
431 renderTarget->addRef();
\r
434 if(this->renderTarget)
\r
436 this->renderTarget->release();
\r
439 this->renderTarget = renderTarget;
\r
441 Renderer::setRenderTarget(0, renderTarget);
\r
444 void Device::setScissorRect(const sw::Rect &rect)
\r
446 scissorRect = rect;
\r
449 void Device::setVertexShader(VertexShader *vertexShader)
\r
451 this->vertexShader = vertexShader;
\r
452 vertexShaderDirty = true;
\r
455 void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)
\r
457 for(unsigned int i = 0; i < count && startRegister + i < 256; i++)
\r
459 vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0];
\r
460 vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1];
\r
461 vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2];
\r
462 vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3];
\r
465 vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty);
\r
466 vertexShaderDirty = true; // Reload DEF constants
\r
469 void Device::setViewport(const Viewport &viewport)
\r
471 this->viewport = viewport;
\r
474 bool Device::stretchRect(egl::Image *source, const sw::Rect *sourceRect, egl::Image *dest, const sw::Rect *destRect, bool filter)
\r
476 if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))
\r
478 ERR("Invalid parameters");
\r
482 int sWidth = source->getExternalWidth();
\r
483 int sHeight = source->getExternalHeight();
\r
484 int dWidth = dest->getExternalWidth();
\r
485 int dHeight = dest->getExternalHeight();
\r
492 sRect = *sourceRect;
\r
498 sRect.y1 = sHeight;
\r
510 dRect.y1 = dHeight;
\r
514 bool scaling = (sRect.x1 - sRect.x0 != dRect.x1 - dRect.x0) || (sRect.y1 - sRect.y0 != dRect.y1 - dRect.y0);
\r
515 bool equalFormats = source->getInternalFormat() == dest->getInternalFormat();
\r
516 bool depthStencil = Image::isDepth(source->getInternalFormat()) || Image::isStencil(source->getInternalFormat());
\r
517 bool alpha0xFF = false;
\r
519 if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||
\r
520 (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))
\r
522 equalFormats = true;
\r
526 if(depthStencil) // Copy entirely, internally // FIXME: Check
\r
528 if(source->hasDepth())
\r
530 sw::byte *sourceBuffer = (sw::byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC);
\r
531 sw::byte *destBuffer = (sw::byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC);
\r
533 unsigned int width = source->getInternalWidth();
\r
534 unsigned int height = source->getInternalHeight();
\r
535 unsigned int pitch = source->getInternalPitchB();
\r
537 for(unsigned int y = 0; y < height; y++)
\r
539 memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
\r
541 sourceBuffer += pitch;
\r
542 destBuffer += pitch;
\r
545 source->unlockInternal();
\r
546 dest->unlockInternal();
\r
549 if(source->hasStencil())
\r
551 sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);
\r
552 sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);
\r
554 unsigned int width = source->getInternalWidth();
\r
555 unsigned int height = source->getInternalHeight();
\r
556 unsigned int pitch = source->getStencilPitchB();
\r
558 for(unsigned int y = 0; y < height; y++)
\r
560 memcpy(destBuffer, sourceBuffer, pitch); // FIXME: Only copy width * bytes
\r
562 sourceBuffer += pitch;
\r
563 destBuffer += pitch;
\r
566 source->unlockStencil();
\r
567 dest->unlockStencil();
\r
570 else if(!scaling && equalFormats)
\r
572 unsigned char *sourceBytes = (unsigned char*)source->lockInternal(sRect.x0, sRect.y0, 0, LOCK_READONLY, PUBLIC);
\r
573 unsigned char *destBytes = (unsigned char*)dest->lockInternal(dRect.x0, dRect.y0, 0, LOCK_READWRITE, PUBLIC);
\r
574 unsigned int sourcePitch = source->getInternalPitchB();
\r
575 unsigned int destPitch = dest->getInternalPitchB();
\r
577 unsigned int width = dRect.x1 - dRect.x0;
\r
578 unsigned int height = dRect.y1 - dRect.y0;
\r
579 unsigned int bytes = width * Image::bytes(source->getInternalFormat());
\r
581 for(unsigned int y = 0; y < height; y++)
\r
583 memcpy(destBytes, sourceBytes, bytes);
\r
587 for(unsigned int x = 0; x < width; x++)
\r
589 destBytes[4 * x + 3] = 0xFF;
\r
593 sourceBytes += sourcePitch;
\r
594 destBytes += destPitch;
\r
597 source->unlockInternal();
\r
598 dest->unlockInternal();
\r
602 blit(source, sRect, dest, dRect, scaling && filter);
\r
608 bool Device::bindResources()
\r
610 if(!bindViewport())
\r
612 return false; // Zero-area target region
\r
615 bindShaderConstants();
\r
620 void Device::bindShaderConstants()
\r
622 if(pixelShaderDirty)
\r
626 if(pixelShaderConstantsFDirty)
\r
628 Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty);
\r
631 Renderer::setPixelShader(pixelShader); // Loads shader constants set with DEF
\r
632 pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
\r
639 pixelShaderDirty = false;
\r
642 if(vertexShaderDirty)
\r
646 if(vertexShaderConstantsFDirty)
\r
648 Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty);
\r
651 Renderer::setVertexShader(vertexShader); // Loads shader constants set with DEF
\r
652 vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF; // Shader DEF'ed constants are dirty
\r
656 setVertexShader(0);
\r
659 vertexShaderDirty = false;
\r
663 bool Device::bindViewport()
\r
665 if(viewport.width <= 0 || viewport.height <= 0)
\r
672 if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)
\r
678 scissor.x0 = scissorRect.x0;
\r
679 scissor.x1 = scissorRect.x1;
\r
680 scissor.y0 = scissorRect.y0;
\r
681 scissor.y1 = scissorRect.y1;
\r
683 setScissor(scissor);
\r
688 scissor.x0 = viewport.x0;
\r
689 scissor.x1 = viewport.x0 + viewport.width;
\r
690 scissor.y0 = viewport.y0;
\r
691 scissor.y1 = viewport.y0 + viewport.height;
\r
695 scissor.x0 = max(scissor.x0, 0);
\r
696 scissor.x1 = min(scissor.x1, renderTarget->getExternalWidth());
\r
697 scissor.y0 = max(scissor.y0, 0);
\r
698 scissor.y1 = min(scissor.y1, renderTarget->getExternalHeight());
\r
703 scissor.x0 = max(scissor.x0, 0);
\r
704 scissor.x1 = min(scissor.x1, depthStencil->getExternalWidth());
\r
705 scissor.y0 = max(scissor.y0, 0);
\r
706 scissor.y1 = min(scissor.y1, depthStencil->getExternalHeight());
\r
709 setScissor(scissor);
\r
713 view.x0 = (float)viewport.x0;
\r
714 view.y0 = (float)viewport.y0;
\r
715 view.width = (float)viewport.width;
\r
716 view.height = (float)viewport.height;
\r
717 view.minZ = viewport.minZ;
\r
718 view.maxZ = viewport.maxZ;
\r
720 Renderer::setViewport(view);
\r
725 bool Device::validRectangle(const sw::Rect *rect, egl::Image *surface)
\r
732 if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)
\r
737 if(rect->x0 < 0 || rect->y0 < 0)
\r
742 if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())
\r
750 void Device::finish()
\r