OSDN Git Service

4cfc90c4a76cf709ca24d1e428d58fbd0c9f635f
[android-x86/external-swiftshader.git] / src / Radiance / libRAD / Device.cpp
1 // SwiftShader Software Renderer\r
2 //\r
3 // Copyright(c) 2005-2013 TransGaming Inc.\r
4 //\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
10 //\r
11 \r
12 #include "Device.hpp"\r
13 \r
14 #include "Image.hpp"\r
15 #include "Texture.h"\r
16 \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
27 \r
28 bool localShaderConstants = false;\r
29 \r
30 namespace rad\r
31 {\r
32         using namespace sw;\r
33 \r
34         Device::Device(Context *context) : Renderer(context, true, true, true, true, true), context(context)\r
35         {\r
36                 depthStencil = 0;\r
37                 renderTarget = 0;\r
38 \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
53                 setFogColor(0);\r
54                 setPixelFogMode(FOG_NONE);\r
55                 setFogStart(0.0f);\r
56                 setFogEnd(1.0f);\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
68                 setClipFlags(0);\r
69                 setPointSize(1.0f);\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
87                 setDepthBias(0.0f);\r
88                 setSeparateAlphaBlendEnable(false);\r
89                 setSourceBlendFactorAlpha(BLEND_ONE);\r
90                 setDestBlendFactorAlpha(BLEND_ZERO);\r
91                 setBlendOperationAlpha(BLENDOP_ADD);\r
92                 setPointSpriteEnable(true);\r
93 \r
94                 for(int i = 0; i < 16; i++)\r
95                 {\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
103                 }\r
104 \r
105                 for(int i = 0; i < 4; i++)\r
106                 {\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
114                 }\r
115 \r
116                 for(int i = 0; i < 6; i++)\r
117                 {\r
118                         float plane[4] = {0, 0, 0, 0};\r
119 \r
120                         setClipPlane(i, plane);\r
121                 }\r
122 \r
123                 pixelShader = 0;\r
124                 vertexShader = 0;\r
125 \r
126                 pixelShaderDirty = true;\r
127                 pixelShaderConstantsFDirty = 0;\r
128                 vertexShaderDirty = true;\r
129                 vertexShaderConstantsFDirty = 0;\r
130 \r
131                 for(int i = 0; i < 224; i++)\r
132                 {\r
133                         float zero[4] = {0, 0, 0, 0};\r
134 \r
135                         setPixelShaderConstantF(i, zero, 1);\r
136                 }\r
137 \r
138                 for(int i = 0; i < 256; i++)\r
139                 {\r
140                         float zero[4] = {0, 0, 0, 0};\r
141 \r
142                         setVertexShaderConstantF(i, zero, 1);\r
143                 }\r
144         }\r
145 \r
146         Device::~Device()\r
147         {               \r
148                 if(depthStencil)\r
149                 {\r
150                         depthStencil->release();\r
151                         depthStencil = 0;\r
152                 }\r
153                 \r
154                 if(renderTarget)\r
155                 {\r
156                         renderTarget->release();\r
157                         renderTarget = 0;\r
158                 }\r
159 \r
160                 delete context;\r
161         }\r
162 \r
163         void Device::clearColor(unsigned int color, unsigned int rgbaMask)\r
164         {\r
165                 if(!renderTarget)\r
166                 {\r
167                         return;\r
168                 }\r
169 \r
170                 int x0 = 0;\r
171                 int y0 = 0;\r
172                 int width = renderTarget->getExternalWidth();\r
173                 int height = renderTarget->getExternalHeight();\r
174 \r
175                 if(scissorEnable)   // Clamp against scissor rectangle\r
176                 {\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
181                 }\r
182 \r
183                 renderTarget->clearColorBuffer(color, rgbaMask, x0, y0, width, height);\r
184         }\r
185 \r
186         void Device::clearDepth(float z)\r
187         {\r
188                 if(!depthStencil)\r
189                 {\r
190                         return;\r
191                 }\r
192 \r
193                 if(z > 1) z = 1;\r
194                 if(z < 0) z = 0;\r
195 \r
196                 int x0 = 0;\r
197                 int y0 = 0;\r
198                 int width = depthStencil->getExternalWidth();\r
199                 int height = depthStencil->getExternalHeight();\r
200 \r
201                 if(scissorEnable)   // Clamp against scissor rectangle\r
202                 {\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
207                 }\r
208                         \r
209                 depthStencil->clearDepthBuffer(z, x0, y0, width, height);\r
210         }\r
211 \r
212         void Device::clearStencil(unsigned int stencil, unsigned int mask)\r
213         {\r
214                 if(!depthStencil)\r
215                 {\r
216                         return;\r
217                 }\r
218 \r
219                 int x0 = 0;\r
220                 int y0 = 0;\r
221                 int width = depthStencil->getExternalWidth();\r
222                 int height = depthStencil->getExternalHeight();\r
223 \r
224                 if(scissorEnable)   // Clamp against scissor rectangle\r
225                 {\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
230                 }\r
231 \r
232                 depthStencil->clearStencilBuffer(stencil, mask, x0, y0, width, height);\r
233         }\r
234 \r
235         Image *Device::createDepthStencilSurface(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool discard)\r
236         {\r
237                 if(width == 0 || height == 0 || height > OUTLINE_RESOLUTION)\r
238                 {\r
239                         ERR("Invalid parameters");\r
240                         return 0;\r
241                 }\r
242                 \r
243                 bool lockable = true;\r
244 \r
245                 switch(format)\r
246                 {\r
247         //      case FORMAT_D15S1:\r
248                 case FORMAT_D24S8:\r
249                 case FORMAT_D24X8:\r
250         //      case FORMAT_D24X4S4:\r
251                 case FORMAT_D24FS8:\r
252                 case FORMAT_D32:\r
253                 case FORMAT_D16:\r
254                         lockable = false;\r
255                         break;\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
262                         lockable = true;\r
263                         break;\r
264                 default:\r
265                         UNREACHABLE();\r
266                 }\r
267 \r
268                 Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);\r
269 \r
270                 if(!surface)\r
271                 {\r
272                         ERR("Out of memory");\r
273                         return 0;\r
274                 }\r
275 \r
276                 return surface;\r
277         }\r
278 \r
279         Image *Device::createRenderTarget(unsigned int width, unsigned int height, sw::Format format, int multiSampleDepth, bool lockable)\r
280         {\r
281                 if(height > OUTLINE_RESOLUTION)\r
282                 {\r
283                         ERR("Invalid parameters");\r
284                         return 0;\r
285                 }\r
286 \r
287                 Image *surface = new Image(0, width, height, format, multiSampleDepth, lockable, true);\r
288 \r
289                 if(!surface)\r
290                 {\r
291                         ERR("Out of memory");\r
292                         return 0;\r
293                 }\r
294                 \r
295                 return surface;\r
296         }\r
297 \r
298         void Device::drawIndexedPrimitive(PrimitiveType type, unsigned int indexOffset, unsigned int primitiveCount, int indexSize)\r
299         {\r
300                 if(!bindResources() || !primitiveCount)\r
301                 {\r
302                         return;\r
303                 }\r
304 \r
305                 DrawType drawType;\r
306 \r
307                 if(indexSize == 4)\r
308                 {\r
309                         switch(type)\r
310                         {\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
319                         }\r
320                 }\r
321                 else if(indexSize == 2)\r
322                 {\r
323                         switch(type)\r
324                         {\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
333                         }\r
334                 }\r
335                 else if(indexSize == 1)\r
336                 {\r
337                         switch(type)\r
338                         {\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
347                         }\r
348                 }\r
349                 else UNREACHABLE();\r
350 \r
351                 draw(drawType, indexOffset, primitiveCount);\r
352         }\r
353 \r
354         void Device::drawPrimitive(PrimitiveType primitiveType, unsigned int primitiveCount)\r
355         {\r
356                 if(!bindResources() || !primitiveCount)\r
357                 {\r
358                         return;\r
359                 }\r
360 \r
361                 setIndexBuffer(0);\r
362                 \r
363                 DrawType drawType;\r
364 \r
365                 switch(primitiveType)\r
366                 {\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
375                 }\r
376 \r
377                 draw(drawType, 0, primitiveCount);\r
378         }\r
379 \r
380         void Device::setDepthStencilSurface(egl::Image *depthStencil)\r
381         {\r
382                 if(this->depthStencil == depthStencil)\r
383                 {\r
384                         return;\r
385                 }\r
386 \r
387                 if(depthStencil)\r
388                 {\r
389                         depthStencil->addRef();\r
390                 }\r
391 \r
392                 if(this->depthStencil)\r
393                 {\r
394                         this->depthStencil->release();\r
395                 }\r
396 \r
397                 this->depthStencil = depthStencil;\r
398 \r
399                 setDepthStencil(depthStencil);\r
400         }\r
401 \r
402         void Device::setPixelShader(PixelShader *pixelShader)\r
403         {\r
404                 this->pixelShader = pixelShader;\r
405                 pixelShaderDirty = true;\r
406         }\r
407 \r
408         void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)\r
409         {\r
410                 for(unsigned int i = 0; i < count && startRegister + i < 224; i++)\r
411                 {\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
416                 }\r
417 \r
418                 pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty);\r
419                 pixelShaderDirty = true;   // Reload DEF constants\r
420         }\r
421 \r
422         void Device::setScissorEnable(bool enable)\r
423         {\r
424                 scissorEnable = enable;\r
425         }\r
426 \r
427         void Device::setRenderTarget(egl::Image *renderTarget)\r
428         {\r
429                 if(renderTarget)\r
430                 {\r
431                         renderTarget->addRef();\r
432                 }\r
433 \r
434                 if(this->renderTarget)\r
435                 {\r
436                         this->renderTarget->release();\r
437                 }\r
438 \r
439                 this->renderTarget = renderTarget;\r
440 \r
441                 Renderer::setRenderTarget(0, renderTarget);\r
442         }\r
443 \r
444         void Device::setScissorRect(const sw::Rect &rect)\r
445         {\r
446                 scissorRect = rect;\r
447         }\r
448 \r
449         void Device::setVertexShader(VertexShader *vertexShader)\r
450         {\r
451                 this->vertexShader = vertexShader;\r
452                 vertexShaderDirty = true;\r
453         }\r
454 \r
455         void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count)\r
456         {\r
457                 for(unsigned int i = 0; i < count && startRegister + i < 256; i++)\r
458                 {\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
463                 }\r
464                         \r
465                 vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty);\r
466                 vertexShaderDirty = true;   // Reload DEF constants\r
467         }\r
468 \r
469         void Device::setViewport(const Viewport &viewport)\r
470         {\r
471                 this->viewport = viewport;\r
472         }\r
473 \r
474         bool Device::stretchRect(egl::Image *source, const sw::Rect *sourceRect, egl::Image *dest, const sw::Rect *destRect, bool filter)\r
475         {\r
476                 if(!source || !dest || !validRectangle(sourceRect, source) || !validRectangle(destRect, dest))\r
477                 {\r
478                         ERR("Invalid parameters");\r
479                         return false;\r
480                 }\r
481                 \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
486 \r
487                 Rect sRect;\r
488                 Rect dRect;\r
489 \r
490                 if(sourceRect)\r
491                 {\r
492                         sRect = *sourceRect;\r
493                 }\r
494                 else\r
495                 {\r
496                         sRect.y0 = 0;\r
497                         sRect.x0 = 0;\r
498                         sRect.y1 = sHeight;\r
499                         sRect.x1 = sWidth;\r
500                 }\r
501 \r
502                 if(destRect)\r
503                 {\r
504                         dRect = *destRect;\r
505                 }\r
506                 else\r
507                 {\r
508                         dRect.y0 = 0;\r
509                         dRect.x0 = 0;\r
510                         dRect.y1 = dHeight;\r
511                         dRect.x1 = dWidth;\r
512                 }\r
513 \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
518 \r
519                 if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) ||\r
520                    (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8))\r
521                 {\r
522                         equalFormats = true;\r
523                         alpha0xFF = true;\r
524                 }\r
525 \r
526                 if(depthStencil)   // Copy entirely, internally   // FIXME: Check\r
527                 {\r
528                         if(source->hasDepth())\r
529                         {\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
532 \r
533                                 unsigned int width = source->getInternalWidth();\r
534                                 unsigned int height = source->getInternalHeight();\r
535                                 unsigned int pitch = source->getInternalPitchB();\r
536 \r
537                                 for(unsigned int y = 0; y < height; y++)\r
538                                 {\r
539                                         memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes\r
540 \r
541                                         sourceBuffer += pitch;\r
542                                         destBuffer += pitch;\r
543                                 }\r
544 \r
545                                 source->unlockInternal();\r
546                                 dest->unlockInternal();\r
547                         }\r
548 \r
549                         if(source->hasStencil())\r
550                         {\r
551                                 sw::byte *sourceBuffer = (sw::byte*)source->lockStencil(0, PUBLIC);\r
552                                 sw::byte *destBuffer = (sw::byte*)dest->lockStencil(0, PUBLIC);\r
553 \r
554                                 unsigned int width = source->getInternalWidth();\r
555                                 unsigned int height = source->getInternalHeight();\r
556                                 unsigned int pitch = source->getStencilPitchB();\r
557 \r
558                                 for(unsigned int y = 0; y < height; y++)\r
559                                 {\r
560                                         memcpy(destBuffer, sourceBuffer, pitch);   // FIXME: Only copy width * bytes\r
561 \r
562                                         sourceBuffer += pitch;\r
563                                         destBuffer += pitch;\r
564                                 }\r
565 \r
566                                 source->unlockStencil();\r
567                                 dest->unlockStencil();\r
568                         }\r
569                 }\r
570                 else if(!scaling && equalFormats)\r
571                 {\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
576 \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
580 \r
581                         for(unsigned int y = 0; y < height; y++)\r
582                         {\r
583                                 memcpy(destBytes, sourceBytes, bytes);\r
584 \r
585                                 if(alpha0xFF)\r
586                                 {\r
587                                         for(unsigned int x = 0; x < width; x++)\r
588                                         {\r
589                                                 destBytes[4 * x + 3] = 0xFF;\r
590                                         }\r
591                                 }\r
592                                 \r
593                                 sourceBytes += sourcePitch;\r
594                                 destBytes += destPitch;\r
595                         }\r
596 \r
597                         source->unlockInternal();\r
598                         dest->unlockInternal();\r
599                 }\r
600                 else\r
601                 {\r
602                         blit(source, sRect, dest, dRect, scaling && filter);\r
603                 }\r
604 \r
605                 return true;\r
606         }\r
607 \r
608         bool Device::bindResources()\r
609         {\r
610                 if(!bindViewport())\r
611                 {\r
612                         return false;   // Zero-area target region\r
613                 }\r
614 \r
615                 bindShaderConstants();\r
616 \r
617                 return true;\r
618         }\r
619 \r
620         void Device::bindShaderConstants()\r
621         {\r
622                 if(pixelShaderDirty)\r
623                 {\r
624                         if(pixelShader)\r
625                         {\r
626                                 if(pixelShaderConstantsFDirty)\r
627                                 {\r
628                                         Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty);\r
629                                 }\r
630 \r
631                                 Renderer::setPixelShader(pixelShader);   // Loads shader constants set with DEF\r
632                                 pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF;   // Shader DEF'ed constants are dirty\r
633                         }\r
634                         else\r
635                         {\r
636                                 setPixelShader(0);\r
637                         }\r
638 \r
639                         pixelShaderDirty = false;\r
640                 }\r
641 \r
642                 if(vertexShaderDirty)\r
643                 {\r
644                         if(vertexShader)\r
645                         {\r
646                                 if(vertexShaderConstantsFDirty)\r
647                                 {\r
648                                         Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty);\r
649                                 }\r
650                 \r
651                                 Renderer::setVertexShader(vertexShader);   // Loads shader constants set with DEF\r
652                                 vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF;   // Shader DEF'ed constants are dirty\r
653                         }\r
654                         else\r
655                         {\r
656                                 setVertexShader(0);\r
657                         }\r
658 \r
659                         vertexShaderDirty = false;\r
660                 }\r
661         }\r
662         \r
663         bool Device::bindViewport()\r
664         {\r
665                 if(viewport.width <= 0 || viewport.height <= 0)\r
666                 {\r
667                         return false;\r
668                 }\r
669 \r
670                 if(scissorEnable)\r
671                 {\r
672                         if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1)\r
673                         {\r
674                                 return false;\r
675                         }\r
676 \r
677                         sw::Rect scissor;\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
682                         \r
683                         setScissor(scissor);\r
684                 }\r
685                 else\r
686                 {\r
687                         sw::Rect 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
692                         \r
693                         if(renderTarget)\r
694                         {\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
699                         }\r
700 \r
701                         if(depthStencil)\r
702                         {\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
707                         }\r
708 \r
709                         setScissor(scissor);\r
710                 }\r
711 \r
712                 sw::Viewport view;\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
719                 \r
720                 Renderer::setViewport(view);\r
721 \r
722                 return true;\r
723         }\r
724 \r
725         bool Device::validRectangle(const sw::Rect *rect, egl::Image *surface)\r
726         {\r
727                 if(!rect)\r
728                 {\r
729                         return true;\r
730                 }\r
731 \r
732                 if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0)\r
733                 {\r
734                         return false;\r
735                 }\r
736 \r
737                 if(rect->x0 < 0 || rect->y0 < 0)\r
738                 {\r
739                         return false;\r
740                 }\r
741 \r
742                 if(rect->x1 > (int)surface->getWidth() || rect->y1 > (int)surface->getHeight())\r
743                 {\r
744                         return false;\r
745                 }\r
746 \r
747                 return true;\r
748         }\r
749 \r
750         void Device::finish()\r
751         {\r
752                 synchronize();\r
753         }\r
754 }\r