1 | // Copyright 2016 The SwiftShader Authors. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #include "Device.hpp" |
16 | |
17 | #include "common/Image.hpp" |
18 | #include "Texture.h" |
19 | |
20 | #include "Renderer/Renderer.hpp" |
21 | #include "Renderer/Clipper.hpp" |
22 | #include "Shader/PixelShader.hpp" |
23 | #include "Shader/VertexShader.hpp" |
24 | #include "Main/Config.hpp" |
25 | #include "Main/FrameBuffer.hpp" |
26 | #include "Common/Math.hpp" |
27 | #include "Common/Configurator.hpp" |
28 | #include "Common/Memory.hpp" |
29 | #include "Common/Timer.hpp" |
30 | #include "../common/debug.h" |
31 | |
32 | namespace es2 |
33 | { |
34 | using namespace sw; |
35 | |
36 | Device::Device(Context *context) : Renderer(context, OpenGL, true), context(context) |
37 | { |
38 | for(int i = 0; i < RENDERTARGETS; i++) |
39 | { |
40 | renderTarget[i] = nullptr; |
41 | } |
42 | |
43 | depthBuffer = nullptr; |
44 | stencilBuffer = nullptr; |
45 | |
46 | setDepthBufferEnable(true); |
47 | setFillMode(FILL_SOLID); |
48 | setShadingMode(SHADING_GOURAUD); |
49 | setDepthWriteEnable(true); |
50 | setAlphaTestEnable(false); |
51 | setSourceBlendFactor(BLEND_ONE); |
52 | setDestBlendFactor(BLEND_ZERO); |
53 | setCullMode(CULL_COUNTERCLOCKWISE, true); |
54 | setDepthCompare(DEPTH_LESSEQUAL); |
55 | setAlphaReference(127.5f); |
56 | setAlphaCompare(ALPHA_ALWAYS); |
57 | setAlphaBlendEnable(false); |
58 | setFogEnable(false); |
59 | setSpecularEnable(false); |
60 | setFogColor(0); |
61 | setPixelFogMode(FOG_NONE); |
62 | setFogStart(0.0f); |
63 | setFogEnd(1.0f); |
64 | setFogDensity(1.0f); |
65 | setRangeFogEnable(false); |
66 | setStencilEnable(false); |
67 | setStencilFailOperation(OPERATION_KEEP); |
68 | setStencilZFailOperation(OPERATION_KEEP); |
69 | setStencilPassOperation(OPERATION_KEEP); |
70 | setStencilCompare(STENCIL_ALWAYS); |
71 | setStencilReference(0); |
72 | setStencilMask(0xFFFFFFFF); |
73 | setStencilWriteMask(0xFFFFFFFF); |
74 | setVertexFogMode(FOG_NONE); |
75 | setClipFlags(0); |
76 | setPointSize(1.0f); |
77 | setPointSizeMin(0.125f); |
78 | setPointSizeMax(8192.0f); |
79 | setBlendOperation(BLENDOP_ADD); |
80 | scissorEnable = false; |
81 | setSlopeDepthBias(0.0f); |
82 | setTwoSidedStencil(false); |
83 | setStencilFailOperationCCW(OPERATION_KEEP); |
84 | setStencilZFailOperationCCW(OPERATION_KEEP); |
85 | setStencilPassOperationCCW(OPERATION_KEEP); |
86 | setStencilCompareCCW(STENCIL_ALWAYS); |
87 | setBlendConstant(0xFFFFFFFF); |
88 | setWriteSRGB(false); |
89 | setDepthBias(0.0f); |
90 | setSeparateAlphaBlendEnable(false); |
91 | setSourceBlendFactorAlpha(BLEND_ONE); |
92 | setDestBlendFactorAlpha(BLEND_ZERO); |
93 | setBlendOperationAlpha(BLENDOP_ADD); |
94 | setPointSpriteEnable(true); |
95 | setColorLogicOpEnabled(false); |
96 | setLogicalOperation(LOGICALOP_COPY); |
97 | |
98 | for(int i = 0; i < 16; i++) |
99 | { |
100 | setAddressingModeU(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP); |
101 | setAddressingModeV(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP); |
102 | setAddressingModeW(sw::SAMPLER_PIXEL, i, ADDRESSING_WRAP); |
103 | setBorderColor(sw::SAMPLER_PIXEL, i, 0x00000000); |
104 | setTextureFilter(sw::SAMPLER_PIXEL, i, FILTER_POINT); |
105 | setMipmapFilter(sw::SAMPLER_PIXEL, i, MIPMAP_NONE); |
106 | setMipmapLOD(sw::SAMPLER_PIXEL, i, 0.0f); |
107 | } |
108 | |
109 | for(int i = 0; i < 4; i++) |
110 | { |
111 | setAddressingModeU(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP); |
112 | setAddressingModeV(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP); |
113 | setAddressingModeW(sw::SAMPLER_VERTEX, i, ADDRESSING_WRAP); |
114 | setBorderColor(sw::SAMPLER_VERTEX, i, 0x00000000); |
115 | setTextureFilter(sw::SAMPLER_VERTEX, i, FILTER_POINT); |
116 | setMipmapFilter(sw::SAMPLER_VERTEX, i, MIPMAP_NONE); |
117 | setMipmapLOD(sw::SAMPLER_VERTEX, i, 0.0f); |
118 | } |
119 | |
120 | for(int i = 0; i < 6; i++) |
121 | { |
122 | float plane[4] = {0, 0, 0, 0}; |
123 | |
124 | setClipPlane(i, plane); |
125 | } |
126 | |
127 | pixelShader = nullptr; |
128 | vertexShader = nullptr; |
129 | |
130 | pixelShaderDirty = true; |
131 | pixelShaderConstantsFDirty = 0; |
132 | vertexShaderDirty = true; |
133 | vertexShaderConstantsFDirty = 0; |
134 | |
135 | for(int i = 0; i < FRAGMENT_UNIFORM_VECTORS; i++) |
136 | { |
137 | float zero[4] = {0, 0, 0, 0}; |
138 | |
139 | setPixelShaderConstantF(i, zero, 1); |
140 | } |
141 | |
142 | for(int i = 0; i < VERTEX_UNIFORM_VECTORS; i++) |
143 | { |
144 | float zero[4] = {0, 0, 0, 0}; |
145 | |
146 | setVertexShaderConstantF(i, zero, 1); |
147 | } |
148 | } |
149 | |
150 | Device::~Device() |
151 | { |
152 | for(int i = 0; i < RENDERTARGETS; i++) |
153 | { |
154 | if(renderTarget[i]) |
155 | { |
156 | renderTarget[i]->release(); |
157 | renderTarget[i] = nullptr; |
158 | } |
159 | } |
160 | |
161 | if(depthBuffer) |
162 | { |
163 | depthBuffer->release(); |
164 | depthBuffer = nullptr; |
165 | } |
166 | |
167 | if(stencilBuffer) |
168 | { |
169 | stencilBuffer->release(); |
170 | stencilBuffer = nullptr; |
171 | } |
172 | |
173 | delete context; |
174 | } |
175 | |
176 | // This object has to be mem aligned |
177 | void* Device::operator new(size_t size) |
178 | { |
179 | ASSERT(size == sizeof(Device)); // This operator can't be called from a derived class |
180 | return sw::allocate(sizeof(Device), 16); |
181 | } |
182 | |
183 | void Device::operator delete(void * mem) |
184 | { |
185 | sw::deallocate(mem); |
186 | } |
187 | |
188 | void Device::clearColor(float red, float green, float blue, float alpha, unsigned int rgbaMask) |
189 | { |
190 | if(!rgbaMask) |
191 | { |
192 | return; |
193 | } |
194 | |
195 | float rgba[4]; |
196 | rgba[0] = red; |
197 | rgba[1] = green; |
198 | rgba[2] = blue; |
199 | rgba[3] = alpha; |
200 | |
201 | for(int i = 0; i < RENDERTARGETS; ++i) |
202 | { |
203 | if(renderTarget[i]) |
204 | { |
205 | sw::Rect clearRect = renderTarget[i]->getRect(); |
206 | |
207 | if(scissorEnable) |
208 | { |
209 | clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1); |
210 | } |
211 | |
212 | clear(rgba, FORMAT_A32B32G32R32F, renderTarget[i], clearRect, rgbaMask); |
213 | } |
214 | } |
215 | } |
216 | |
217 | void Device::clearDepth(float z) |
218 | { |
219 | if(!depthBuffer) |
220 | { |
221 | return; |
222 | } |
223 | |
224 | z = clamp01(z); |
225 | sw::Rect clearRect = depthBuffer->getRect(); |
226 | |
227 | if(scissorEnable) |
228 | { |
229 | clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1); |
230 | } |
231 | |
232 | depthBuffer->clearDepth(z, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height()); |
233 | } |
234 | |
235 | void Device::clearStencil(unsigned int stencil, unsigned int mask) |
236 | { |
237 | if(!stencilBuffer) |
238 | { |
239 | return; |
240 | } |
241 | |
242 | sw::Rect clearRect = stencilBuffer->getRect(); |
243 | |
244 | if(scissorEnable) |
245 | { |
246 | clearRect.clip(scissorRect.x0, scissorRect.y0, scissorRect.x1, scissorRect.y1); |
247 | } |
248 | |
249 | stencilBuffer->clearStencil(stencil, mask, clearRect.x0, clearRect.y0, clearRect.width(), clearRect.height()); |
250 | } |
251 | |
252 | void Device::drawIndexedPrimitive(sw::DrawType type, unsigned int indexOffset, unsigned int primitiveCount) |
253 | { |
254 | if(!bindResources() || !primitiveCount) |
255 | { |
256 | return; |
257 | } |
258 | |
259 | draw(type, indexOffset, primitiveCount); |
260 | } |
261 | |
262 | void Device::drawPrimitive(sw::DrawType type, unsigned int primitiveCount) |
263 | { |
264 | if(!bindResources() || !primitiveCount) |
265 | { |
266 | return; |
267 | } |
268 | |
269 | setIndexBuffer(nullptr); |
270 | |
271 | draw(type, 0, primitiveCount); |
272 | } |
273 | |
274 | void Device::setPixelShader(const PixelShader *pixelShader) |
275 | { |
276 | this->pixelShader = pixelShader; |
277 | pixelShaderDirty = true; |
278 | } |
279 | |
280 | void Device::setPixelShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count) |
281 | { |
282 | for(unsigned int i = 0; i < count && startRegister + i < FRAGMENT_UNIFORM_VECTORS; i++) |
283 | { |
284 | pixelShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0]; |
285 | pixelShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1]; |
286 | pixelShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2]; |
287 | pixelShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3]; |
288 | } |
289 | |
290 | pixelShaderConstantsFDirty = max(startRegister + count, pixelShaderConstantsFDirty); |
291 | pixelShaderDirty = true; // Reload DEF constants |
292 | } |
293 | |
294 | void Device::setScissorEnable(bool enable) |
295 | { |
296 | scissorEnable = enable; |
297 | } |
298 | |
299 | void Device::setRenderTarget(int index, egl::Image *renderTarget, unsigned int layer) |
300 | { |
301 | if(renderTarget) |
302 | { |
303 | renderTarget->addRef(); |
304 | } |
305 | |
306 | if(this->renderTarget[index]) |
307 | { |
308 | this->renderTarget[index]->release(); |
309 | } |
310 | |
311 | this->renderTarget[index] = renderTarget; |
312 | |
313 | Renderer::setRenderTarget(index, renderTarget, layer); |
314 | } |
315 | |
316 | void Device::setDepthBuffer(egl::Image *depthBuffer, unsigned int layer) |
317 | { |
318 | if(this->depthBuffer == depthBuffer) |
319 | { |
320 | return; |
321 | } |
322 | |
323 | if(depthBuffer) |
324 | { |
325 | depthBuffer->addRef(); |
326 | } |
327 | |
328 | if(this->depthBuffer) |
329 | { |
330 | this->depthBuffer->release(); |
331 | } |
332 | |
333 | this->depthBuffer = depthBuffer; |
334 | |
335 | Renderer::setDepthBuffer(depthBuffer, layer); |
336 | } |
337 | |
338 | void Device::setStencilBuffer(egl::Image *stencilBuffer, unsigned int layer) |
339 | { |
340 | if(this->stencilBuffer == stencilBuffer) |
341 | { |
342 | return; |
343 | } |
344 | |
345 | if(stencilBuffer) |
346 | { |
347 | stencilBuffer->addRef(); |
348 | } |
349 | |
350 | if(this->stencilBuffer) |
351 | { |
352 | this->stencilBuffer->release(); |
353 | } |
354 | |
355 | this->stencilBuffer = stencilBuffer; |
356 | |
357 | Renderer::setStencilBuffer(stencilBuffer, layer); |
358 | } |
359 | |
360 | void Device::setScissorRect(const sw::Rect &rect) |
361 | { |
362 | scissorRect = rect; |
363 | } |
364 | |
365 | void Device::setVertexShader(const VertexShader *vertexShader) |
366 | { |
367 | this->vertexShader = vertexShader; |
368 | vertexShaderDirty = true; |
369 | } |
370 | |
371 | void Device::setVertexShaderConstantF(unsigned int startRegister, const float *constantData, unsigned int count) |
372 | { |
373 | for(unsigned int i = 0; i < count && startRegister + i < VERTEX_UNIFORM_VECTORS; i++) |
374 | { |
375 | vertexShaderConstantF[startRegister + i][0] = constantData[i * 4 + 0]; |
376 | vertexShaderConstantF[startRegister + i][1] = constantData[i * 4 + 1]; |
377 | vertexShaderConstantF[startRegister + i][2] = constantData[i * 4 + 2]; |
378 | vertexShaderConstantF[startRegister + i][3] = constantData[i * 4 + 3]; |
379 | } |
380 | |
381 | vertexShaderConstantsFDirty = max(startRegister + count, vertexShaderConstantsFDirty); |
382 | vertexShaderDirty = true; // Reload DEF constants |
383 | } |
384 | |
385 | void Device::setViewport(const Viewport &viewport) |
386 | { |
387 | this->viewport = viewport; |
388 | } |
389 | |
390 | void Device::copyBuffer(byte *sourceBuffer, byte *destBuffer, unsigned int width, unsigned int height, unsigned int sourcePitch, unsigned int destPitch, unsigned int bytes, bool flipX, bool flipY) |
391 | { |
392 | if(flipX) |
393 | { |
394 | if(flipY) |
395 | { |
396 | sourceBuffer += (height - 1) * sourcePitch; |
397 | for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch) |
398 | { |
399 | byte *srcX = sourceBuffer + (width - 1) * bytes; |
400 | byte *dstX = destBuffer; |
401 | for(unsigned int x = 0; x < width; ++x, dstX += bytes, srcX -= bytes) |
402 | { |
403 | memcpy(dstX, srcX, bytes); |
404 | } |
405 | } |
406 | } |
407 | else |
408 | { |
409 | for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch) |
410 | { |
411 | byte *srcX = sourceBuffer + (width - 1) * bytes; |
412 | byte *dstX = destBuffer; |
413 | for(unsigned int x = 0; x < width; ++x, dstX += bytes, srcX -= bytes) |
414 | { |
415 | memcpy(dstX, srcX, bytes); |
416 | } |
417 | } |
418 | } |
419 | } |
420 | else |
421 | { |
422 | unsigned int widthB = width * bytes; |
423 | |
424 | if(flipY) |
425 | { |
426 | sourceBuffer += (height - 1) * sourcePitch; |
427 | for(unsigned int y = 0; y < height; ++y, sourceBuffer -= sourcePitch, destBuffer += destPitch) |
428 | { |
429 | memcpy(destBuffer, sourceBuffer, widthB); |
430 | } |
431 | } |
432 | else |
433 | { |
434 | for(unsigned int y = 0; y < height; ++y, sourceBuffer += sourcePitch, destBuffer += destPitch) |
435 | { |
436 | memcpy(destBuffer, sourceBuffer, widthB); |
437 | } |
438 | } |
439 | } |
440 | } |
441 | |
442 | bool Device::stretchRect(sw::Surface *source, const sw::SliceRectF *sourceRect, sw::Surface *dest, const sw::SliceRect *destRect, unsigned char flags) |
443 | { |
444 | if(!source || !dest) |
445 | { |
446 | ERR("Invalid parameters" ); |
447 | return false; |
448 | } |
449 | |
450 | int sWidth = source->getWidth(); |
451 | int sHeight = source->getHeight(); |
452 | int dWidth = dest->getWidth(); |
453 | int dHeight = dest->getHeight(); |
454 | |
455 | if(sourceRect && destRect && |
456 | (sourceRect->width() == 0.0f || !std::isfinite(sourceRect->width()) || |
457 | sourceRect->height() == 0.0f || !std::isfinite(sourceRect->height()) || |
458 | destRect->width() == 0.0f || destRect->height() == 0.0f)) |
459 | { |
460 | return true; // No work to do. |
461 | } |
462 | |
463 | bool flipX = false; |
464 | bool flipY = false; |
465 | if(sourceRect && destRect) |
466 | { |
467 | flipX = (sourceRect->x0 < sourceRect->x1) ^ (destRect->x0 < destRect->x1); |
468 | flipY = (sourceRect->y0 < sourceRect->y1) ^ (destRect->y0 < destRect->y1); |
469 | } |
470 | else if(sourceRect) |
471 | { |
472 | flipX = (sourceRect->x0 > sourceRect->x1); |
473 | flipY = (sourceRect->y0 > sourceRect->y1); |
474 | } |
475 | else if(destRect) |
476 | { |
477 | flipX = (destRect->x0 > destRect->x1); |
478 | flipY = (destRect->y0 > destRect->y1); |
479 | } |
480 | |
481 | SliceRectF sRect; |
482 | SliceRect dRect; |
483 | |
484 | if(sourceRect) |
485 | { |
486 | sRect.x0 = sourceRect->x0; |
487 | sRect.x1 = sourceRect->x1; |
488 | sRect.y0 = sourceRect->y0; |
489 | sRect.y1 = sourceRect->y1; |
490 | sRect.slice = sourceRect->slice; |
491 | |
492 | if(sRect.x0 > sRect.x1) |
493 | { |
494 | swap(sRect.x0, sRect.x1); |
495 | } |
496 | |
497 | if(sRect.y0 > sRect.y1) |
498 | { |
499 | swap(sRect.y0, sRect.y1); |
500 | } |
501 | } |
502 | else |
503 | { |
504 | sRect.y0 = 0.0f; |
505 | sRect.x0 = 0.0f; |
506 | sRect.y1 = (float)sHeight; |
507 | sRect.x1 = (float)sWidth; |
508 | } |
509 | |
510 | if(destRect) |
511 | { |
512 | dRect = *destRect; |
513 | |
514 | if(dRect.x0 > dRect.x1) |
515 | { |
516 | swap(dRect.x0, dRect.x1); |
517 | } |
518 | |
519 | if(dRect.y0 > dRect.y1) |
520 | { |
521 | swap(dRect.y0, dRect.y1); |
522 | } |
523 | } |
524 | else |
525 | { |
526 | dRect.y0 = 0; |
527 | dRect.x0 = 0; |
528 | dRect.y1 = dHeight; |
529 | dRect.x1 = dWidth; |
530 | } |
531 | |
532 | sw::Rect srcClipRect(0, 0, sWidth, sHeight); |
533 | if (!ClipSrcRect(sRect, dRect, srcClipRect, flipX, flipY)) |
534 | { |
535 | return true; |
536 | } |
537 | |
538 | sw::Rect dstClipRect(0, 0, dWidth, dHeight); |
539 | if (!ClipDstRect(sRect, dRect, dstClipRect, flipX, flipY)) |
540 | { |
541 | return true; |
542 | } |
543 | |
544 | if((sRect.width() == 0) || (sRect.height() == 0) || |
545 | (dRect.width() == 0) || (dRect.height() == 0) || |
546 | !std::isfinite(sRect.width()) || !std::isfinite(sRect.height())) |
547 | { |
548 | return true; // no work to do |
549 | } |
550 | |
551 | if(!validRectangle(&sRect, source) || !validRectangle(&dRect, dest)) |
552 | { |
553 | ERR("Invalid parameters" ); |
554 | return false; |
555 | } |
556 | |
557 | bool isDepth = (flags & Device::DEPTH_BUFFER) && Surface::isDepth(source->getInternalFormat()); |
558 | bool isStencil = (flags & Device::STENCIL_BUFFER) && Surface::isStencil(source->getInternalFormat()); |
559 | bool isColor = (flags & Device::COLOR_BUFFER) == Device::COLOR_BUFFER; |
560 | |
561 | if(!isColor && !isDepth && !isStencil) |
562 | { |
563 | return true; |
564 | } |
565 | |
566 | int sourceSliceB = isStencil ? source->getStencilSliceB() : source->getInternalSliceB(); |
567 | int destSliceB = isStencil ? dest->getStencilSliceB() : dest->getInternalSliceB(); |
568 | int sourcePitchB = isStencil ? source->getStencilPitchB() : source->getInternalPitchB(); |
569 | int destPitchB = isStencil ? dest->getStencilPitchB() : dest->getInternalPitchB(); |
570 | |
571 | bool isOutOfBounds = (sRect.x0 < 0.0f) || (sRect.y0 < 0.0f) || (sRect.x1 > (float)sWidth) || (sRect.y1 > (float)sHeight); |
572 | bool scaling = (sRect.width() != (float)dRect.width()) || (sRect.height() != (float)dRect.height()); |
573 | bool equalFormats = source->getInternalFormat() == dest->getInternalFormat(); |
574 | bool hasQuadLayout = Surface::hasQuadLayout(source->getInternalFormat()) || Surface::hasQuadLayout(dest->getInternalFormat()); |
575 | bool fullCopy = (sRect.x0 == 0.0f) && (sRect.y0 == 0.0f) && (dRect.x0 == 0) && (dRect.y0 == 0) && |
576 | (sRect.x1 == (float)sWidth) && (sRect.y1 == (float)sHeight) && (dRect.x1 == dWidth) && (dRect.y1 == dHeight); |
577 | bool alpha0xFF = false; |
578 | bool equalSlice = sourceSliceB == destSliceB; |
579 | bool smallMargin = sourcePitchB <= source->getWidth() * Surface::bytes(source->getInternalFormat()) + 16; |
580 | |
581 | if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) || |
582 | (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8)) |
583 | { |
584 | equalFormats = true; |
585 | alpha0xFF = true; |
586 | } |
587 | |
588 | if(fullCopy && !scaling && !isOutOfBounds && equalFormats && !alpha0xFF && equalSlice && smallMargin && !flipX && !flipY) |
589 | { |
590 | byte *sourceBuffer = isStencil ? (byte*)source->lockStencil(0, 0, 0, PUBLIC) : (byte*)source->lockInternal(0, 0, 0, LOCK_READONLY, PUBLIC); |
591 | byte *destBuffer = isStencil ? (byte*)dest->lockStencil(0, 0, 0, PUBLIC) : (byte*)dest->lockInternal(0, 0, 0, LOCK_DISCARD, PUBLIC); |
592 | |
593 | memcpy(destBuffer, sourceBuffer, sourceSliceB); |
594 | |
595 | isStencil ? source->unlockStencil() : source->unlockInternal(); |
596 | isStencil ? dest->unlockStencil() : dest->unlockInternal(); |
597 | } |
598 | else if(isDepth && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout) |
599 | { |
600 | byte *sourceBuffer = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, 0, LOCK_READONLY, PUBLIC); |
601 | byte *destBuffer = (byte*)dest->lockInternal(dRect.x0, dRect.y0, 0, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC); |
602 | |
603 | copyBuffer(sourceBuffer, destBuffer, dRect.width(), dRect.height(), sourcePitchB, destPitchB, Surface::bytes(source->getInternalFormat()), flipX, flipY); |
604 | |
605 | source->unlockInternal(); |
606 | dest->unlockInternal(); |
607 | } |
608 | else if((flags & Device::COLOR_BUFFER) && !scaling && !isOutOfBounds && equalFormats && !hasQuadLayout) |
609 | { |
610 | byte *sourceBytes = (byte*)source->lockInternal((int)sRect.x0, (int)sRect.y0, sourceRect->slice, LOCK_READONLY, PUBLIC); |
611 | byte *destBytes = (byte*)dest->lockInternal(dRect.x0, dRect.y0, destRect->slice, fullCopy ? LOCK_DISCARD : LOCK_WRITEONLY, PUBLIC); |
612 | |
613 | unsigned int width = dRect.x1 - dRect.x0; |
614 | unsigned int height = dRect.y1 - dRect.y0; |
615 | |
616 | copyBuffer(sourceBytes, destBytes, width, height, sourcePitchB, destPitchB, Surface::bytes(source->getInternalFormat()), flipX, flipY); |
617 | |
618 | if(alpha0xFF) |
619 | { |
620 | for(unsigned int y = 0; y < height; y++) |
621 | { |
622 | for(unsigned int x = 0; x < width; x++) |
623 | { |
624 | destBytes[4 * x + 3] = 0xFF; |
625 | } |
626 | |
627 | destBytes += destPitchB; |
628 | } |
629 | } |
630 | |
631 | source->unlockInternal(); |
632 | dest->unlockInternal(); |
633 | } |
634 | else if(isColor || isDepth || isStencil) |
635 | { |
636 | if(flipX) |
637 | { |
638 | swap(dRect.x0, dRect.x1); |
639 | } |
640 | if(flipY) |
641 | { |
642 | swap(dRect.y0, dRect.y1); |
643 | } |
644 | |
645 | blit(source, sRect, dest, dRect, scaling && (flags & Device::USE_FILTER), isStencil); |
646 | } |
647 | else UNREACHABLE(false); |
648 | |
649 | return true; |
650 | } |
651 | |
652 | bool Device::stretchCube(sw::Surface *source, sw::Surface *dest) |
653 | { |
654 | if(!source || !dest || Surface::isDepth(source->getInternalFormat()) || Surface::isStencil(source->getInternalFormat())) |
655 | { |
656 | ERR("Invalid parameters" ); |
657 | return false; |
658 | } |
659 | |
660 | int sWidth = source->getWidth(); |
661 | int sHeight = source->getHeight(); |
662 | int sDepth = source->getDepth(); |
663 | int dWidth = dest->getWidth(); |
664 | int dHeight = dest->getHeight(); |
665 | int dDepth = dest->getDepth(); |
666 | |
667 | if((sWidth == 0) || (sHeight == 0) || (sDepth == 0) || |
668 | (dWidth == 0) || (dHeight == 0) || (dDepth == 0)) |
669 | { |
670 | return true; // no work to do |
671 | } |
672 | |
673 | bool scaling = (sWidth != dWidth) || (sHeight != dHeight) || (sDepth != dDepth); |
674 | bool equalFormats = source->getInternalFormat() == dest->getInternalFormat(); |
675 | bool alpha0xFF = false; |
676 | |
677 | if((source->getInternalFormat() == FORMAT_A8R8G8B8 && dest->getInternalFormat() == FORMAT_X8R8G8B8) || |
678 | (source->getInternalFormat() == FORMAT_X8R8G8B8 && dest->getInternalFormat() == FORMAT_A8R8G8B8)) |
679 | { |
680 | equalFormats = true; |
681 | alpha0xFF = true; |
682 | } |
683 | |
684 | if(!scaling && equalFormats) |
685 | { |
686 | unsigned int sourcePitch = source->getInternalPitchB(); |
687 | unsigned int destPitch = dest->getInternalPitchB(); |
688 | unsigned int bytes = dWidth * Surface::bytes(source->getInternalFormat()); |
689 | |
690 | for(int z = 0; z < dDepth; z++) |
691 | { |
692 | unsigned char *sourceBytes = (unsigned char*)source->lockInternal(0, 0, z, LOCK_READONLY, PUBLIC); |
693 | unsigned char *destBytes = (unsigned char*)dest->lockInternal(0, 0, z, LOCK_READWRITE, PUBLIC); |
694 | |
695 | for(int y = 0; y < dHeight; y++) |
696 | { |
697 | memcpy(destBytes, sourceBytes, bytes); |
698 | |
699 | if(alpha0xFF) |
700 | { |
701 | for(int x = 0; x < dWidth; x++) |
702 | { |
703 | destBytes[4 * x + 3] = 0xFF; |
704 | } |
705 | } |
706 | |
707 | sourceBytes += sourcePitch; |
708 | destBytes += destPitch; |
709 | } |
710 | |
711 | source->unlockInternal(); |
712 | dest->unlockInternal(); |
713 | } |
714 | } |
715 | else |
716 | { |
717 | blit3D(source, dest); |
718 | } |
719 | |
720 | return true; |
721 | } |
722 | |
723 | bool Device::bindResources() |
724 | { |
725 | if(!bindViewport() && !context->transformFeedbackEnabled) |
726 | { |
727 | return false; // Zero-area target region |
728 | } |
729 | |
730 | bindShaderConstants(); |
731 | |
732 | return true; |
733 | } |
734 | |
735 | void Device::bindShaderConstants() |
736 | { |
737 | if(pixelShaderDirty) |
738 | { |
739 | if(pixelShader) |
740 | { |
741 | if(pixelShaderConstantsFDirty) |
742 | { |
743 | Renderer::setPixelShaderConstantF(0, pixelShaderConstantF[0], pixelShaderConstantsFDirty); |
744 | } |
745 | |
746 | Renderer::setPixelShader(pixelShader); // Loads shader constants set with DEF |
747 | pixelShaderConstantsFDirty = pixelShader->dirtyConstantsF; // Shader DEF'ed constants are dirty |
748 | } |
749 | else |
750 | { |
751 | setPixelShader(0); |
752 | } |
753 | |
754 | pixelShaderDirty = false; |
755 | } |
756 | |
757 | if(vertexShaderDirty) |
758 | { |
759 | if(vertexShader) |
760 | { |
761 | if(vertexShaderConstantsFDirty) |
762 | { |
763 | Renderer::setVertexShaderConstantF(0, vertexShaderConstantF[0], vertexShaderConstantsFDirty); |
764 | } |
765 | |
766 | Renderer::setVertexShader(vertexShader); // Loads shader constants set with DEF |
767 | vertexShaderConstantsFDirty = vertexShader->dirtyConstantsF; // Shader DEF'ed constants are dirty |
768 | } |
769 | else |
770 | { |
771 | setVertexShader(0); |
772 | } |
773 | |
774 | vertexShaderDirty = false; |
775 | } |
776 | } |
777 | |
778 | bool Device::bindViewport() |
779 | { |
780 | if(viewport.width <= 0 || viewport.height <= 0) |
781 | { |
782 | return false; |
783 | } |
784 | |
785 | if(scissorEnable) |
786 | { |
787 | if(scissorRect.x0 >= scissorRect.x1 || scissorRect.y0 >= scissorRect.y1) |
788 | { |
789 | return false; |
790 | } |
791 | |
792 | sw::Rect scissor; |
793 | scissor.x0 = scissorRect.x0; |
794 | scissor.x1 = scissorRect.x1; |
795 | scissor.y0 = scissorRect.y0; |
796 | scissor.y1 = scissorRect.y1; |
797 | |
798 | setScissor(scissor); |
799 | } |
800 | else |
801 | { |
802 | sw::Rect scissor; |
803 | scissor.x0 = viewport.x0; |
804 | scissor.x1 = viewport.x0 + viewport.width; |
805 | scissor.y0 = viewport.y0; |
806 | scissor.y1 = viewport.y0 + viewport.height; |
807 | |
808 | for(int i = 0; i < RENDERTARGETS; ++i) |
809 | { |
810 | if(renderTarget[i]) |
811 | { |
812 | scissor.x0 = max(scissor.x0, 0); |
813 | scissor.x1 = min(scissor.x1, renderTarget[i]->getWidth()); |
814 | scissor.y0 = max(scissor.y0, 0); |
815 | scissor.y1 = min(scissor.y1, renderTarget[i]->getHeight()); |
816 | } |
817 | } |
818 | |
819 | if(depthBuffer) |
820 | { |
821 | scissor.x0 = max(scissor.x0, 0); |
822 | scissor.x1 = min(scissor.x1, depthBuffer->getWidth()); |
823 | scissor.y0 = max(scissor.y0, 0); |
824 | scissor.y1 = min(scissor.y1, depthBuffer->getHeight()); |
825 | } |
826 | |
827 | if(stencilBuffer) |
828 | { |
829 | scissor.x0 = max(scissor.x0, 0); |
830 | scissor.x1 = min(scissor.x1, stencilBuffer->getWidth()); |
831 | scissor.y0 = max(scissor.y0, 0); |
832 | scissor.y1 = min(scissor.y1, stencilBuffer->getHeight()); |
833 | } |
834 | |
835 | // Ensure scissor range is positive |
836 | scissor.x0 = max(scissor.x0, 0); |
837 | scissor.x1 = max(scissor.x1, 0); |
838 | scissor.y0 = max(scissor.y0, 0); |
839 | scissor.y1 = max(scissor.y1, 0); |
840 | |
841 | setScissor(scissor); |
842 | } |
843 | |
844 | sw::Viewport view; |
845 | view.x0 = (float)viewport.x0; |
846 | view.y0 = (float)viewport.y0; |
847 | view.width = (float)viewport.width; |
848 | view.height = (float)viewport.height; |
849 | view.minZ = viewport.minZ; |
850 | view.maxZ = viewport.maxZ; |
851 | |
852 | Renderer::setViewport(view); |
853 | |
854 | return true; |
855 | } |
856 | |
857 | bool Device::validRectangle(const sw::Rect *rect, sw::Surface *surface) |
858 | { |
859 | if(!rect) |
860 | { |
861 | return true; |
862 | } |
863 | |
864 | if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0) |
865 | { |
866 | return false; |
867 | } |
868 | |
869 | if(rect->x0 < 0 || rect->y0 < 0) |
870 | { |
871 | return false; |
872 | } |
873 | |
874 | if(rect->x1 >(int)surface->getWidth() || rect->y1 >(int)surface->getHeight()) |
875 | { |
876 | return false; |
877 | } |
878 | |
879 | return true; |
880 | } |
881 | |
882 | bool Device::validRectangle(const sw::RectF *rect, sw::Surface *surface) |
883 | { |
884 | if(!rect) |
885 | { |
886 | return true; |
887 | } |
888 | |
889 | if(rect->x1 <= rect->x0 || rect->y1 <= rect->y0) |
890 | { |
891 | return false; |
892 | } |
893 | |
894 | if (!std::isfinite(rect->x0) || !std::isfinite(rect->x1) || |
895 | !std::isfinite(rect->y0) || !std::isfinite(rect->y1)) |
896 | { |
897 | return false; |
898 | } |
899 | |
900 | return true; |
901 | } |
902 | |
903 | bool Device::ClipDstRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY) |
904 | { |
905 | if(dstRect.x0 < clipRect.x0) |
906 | { |
907 | float offset = (static_cast<float>(clipRect.x0 - dstRect.x0) / static_cast<float>(dstRect.width())) * srcRect.width(); |
908 | if (!std::isfinite(offset)) |
909 | { |
910 | return false; |
911 | } |
912 | if(flipX) |
913 | { |
914 | srcRect.x1 -= offset; |
915 | } |
916 | else |
917 | { |
918 | srcRect.x0 += offset; |
919 | } |
920 | dstRect.x0 = clipRect.x0; |
921 | } |
922 | if(dstRect.x1 > clipRect.x1) |
923 | { |
924 | float offset = (static_cast<float>(dstRect.x1 - clipRect.x1) / static_cast<float>(dstRect.width())) * srcRect.width(); |
925 | if (!std::isfinite(offset)) |
926 | { |
927 | return false; |
928 | } |
929 | if(flipX) |
930 | { |
931 | srcRect.x0 += offset; |
932 | } |
933 | else |
934 | { |
935 | srcRect.x1 -= offset; |
936 | } |
937 | dstRect.x1 = clipRect.x1; |
938 | } |
939 | if(dstRect.y0 < clipRect.y0) |
940 | { |
941 | float offset = (static_cast<float>(clipRect.y0 - dstRect.y0) / static_cast<float>(dstRect.height())) * srcRect.height(); |
942 | if (!std::isfinite(offset)) |
943 | { |
944 | return false; |
945 | } |
946 | if(flipY) |
947 | { |
948 | srcRect.y1 -= offset; |
949 | } |
950 | else |
951 | { |
952 | srcRect.y0 += offset; |
953 | } |
954 | dstRect.y0 = clipRect.y0; |
955 | } |
956 | if(dstRect.y1 > clipRect.y1) |
957 | { |
958 | float offset = (static_cast<float>(dstRect.y1 - clipRect.y1) / static_cast<float>(dstRect.height())) * srcRect.height(); |
959 | if (!std::isfinite(offset)) |
960 | { |
961 | return false; |
962 | } |
963 | if(flipY) |
964 | { |
965 | srcRect.y0 += offset; |
966 | } |
967 | else |
968 | { |
969 | srcRect.y1 -= offset; |
970 | } |
971 | dstRect.y1 = clipRect.y1; |
972 | } |
973 | return true; |
974 | } |
975 | |
976 | bool Device::ClipSrcRect(sw::RectF &srcRect, sw::Rect &dstRect, sw::Rect &clipRect, bool flipX, bool flipY) |
977 | { |
978 | if(srcRect.x0 < static_cast<float>(clipRect.x0)) |
979 | { |
980 | float ratio = static_cast<float>(dstRect.width()) / srcRect.width(); |
981 | float offsetf = roundf((static_cast<float>(clipRect.x0) - srcRect.x0) * ratio); |
982 | if (!FloatFitsInInt(offsetf) || !std::isfinite(ratio)) |
983 | { |
984 | return false; |
985 | } |
986 | int offset = static_cast<int>(offsetf); |
987 | if(flipX) |
988 | { |
989 | dstRect.x1 -= offset; |
990 | } |
991 | else |
992 | { |
993 | dstRect.x0 += offset; |
994 | } |
995 | srcRect.x0 += offsetf / ratio; |
996 | } |
997 | if(srcRect.x1 > static_cast<float>(clipRect.x1)) |
998 | { |
999 | float ratio = static_cast<float>(dstRect.width()) / srcRect.width(); |
1000 | float offsetf = roundf((srcRect.x1 - static_cast<float>(clipRect.x1)) * ratio); |
1001 | if (!FloatFitsInInt(offsetf) || !std::isfinite(ratio)) |
1002 | { |
1003 | return false; |
1004 | } |
1005 | int offset = static_cast<int>(offsetf); |
1006 | if(flipX) |
1007 | { |
1008 | dstRect.x0 += offset; |
1009 | } |
1010 | else |
1011 | { |
1012 | dstRect.x1 -= offset; |
1013 | } |
1014 | srcRect.x1 -= offsetf / ratio; |
1015 | } |
1016 | if(srcRect.y0 < static_cast<float>(clipRect.y0)) |
1017 | { |
1018 | float ratio = static_cast<float>(dstRect.height()) / srcRect.height(); |
1019 | float offsetf = roundf((static_cast<float>(clipRect.y0) - srcRect.y0) * ratio); |
1020 | if (!FloatFitsInInt(offsetf) || !std::isfinite(ratio)) |
1021 | { |
1022 | return false; |
1023 | } |
1024 | int offset = static_cast<int>(offsetf); |
1025 | if(flipY) |
1026 | { |
1027 | dstRect.y1 -= offset; |
1028 | } |
1029 | else |
1030 | { |
1031 | dstRect.y0 += offset; |
1032 | } |
1033 | srcRect.y0 += offsetf / ratio; |
1034 | } |
1035 | if(srcRect.y1 > static_cast<float>(clipRect.y1)) |
1036 | { |
1037 | float ratio = static_cast<float>(dstRect.height()) / srcRect.height(); |
1038 | float offsetf = roundf((srcRect.y1 - static_cast<float>(clipRect.y1)) * ratio); |
1039 | if (!FloatFitsInInt(offsetf) || !std::isfinite(ratio)) |
1040 | { |
1041 | return false; |
1042 | } |
1043 | int offset = static_cast<int>(offsetf); |
1044 | if(flipY) |
1045 | { |
1046 | dstRect.y0 += offset; |
1047 | } |
1048 | else |
1049 | { |
1050 | dstRect.y1 -= offset; |
1051 | } |
1052 | srcRect.y1 -= offsetf / ratio; |
1053 | } |
1054 | return true; |
1055 | } |
1056 | |
1057 | void Device::finish() |
1058 | { |
1059 | synchronize(); |
1060 | } |
1061 | } |
1062 | |