// Copyright 2016 The SwiftShader Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "QuadRasterizer.hpp" #include "Primitive.hpp" #include "Renderer.hpp" #include "Shader/Constants.hpp" #include "Common/Math.hpp" #include "Common/Debug.hpp" namespace sw { extern bool veryEarlyDepthTest; extern bool complementaryDepthBuffer; extern bool fullPixelPositionRegister; extern int clusterCount; QuadRasterizer::QuadRasterizer(const PixelProcessor::State &state, const PixelShader *pixelShader) : state(state), shader(pixelShader) { } QuadRasterizer::~QuadRasterizer() { } void QuadRasterizer::generate() { #if PERF_PROFILE for(int i = 0; i < PERF_TIMERS; i++) { cycles[i] = 0; } Long pixelTime = Ticks(); #endif constants = *Pointer>(data + OFFSET(DrawData,constants)); occlusion = 0; int clusterCount = Renderer::getClusterCount(); Do { Int yMin = *Pointer(primitive + OFFSET(Primitive,yMin)); Int yMax = *Pointer(primitive + OFFSET(Primitive,yMax)); Int cluster2 = cluster + cluster; yMin += clusterCount * 2 - 2 - cluster2; yMin &= -clusterCount * 2; yMin += cluster2; If(yMin < yMax) { rasterize(yMin, yMax); } primitive += sizeof(Primitive) * state.multiSample; count--; } Until(count == 0) if(state.occlusionEnabled) { UInt clusterOcclusion = *Pointer(data + OFFSET(DrawData,occlusion) + 4 * cluster); clusterOcclusion += occlusion; *Pointer(data + OFFSET(DrawData,occlusion) + 4 * cluster) = clusterOcclusion; } #if PERF_PROFILE cycles[PERF_PIXEL] = Ticks() - pixelTime; for(int i = 0; i < PERF_TIMERS; i++) { *Pointer(data + OFFSET(DrawData,cycles[i]) + 8 * cluster) += cycles[i]; } #endif Return(); } void QuadRasterizer::rasterize(Int &yMin, Int &yMax) { Pointer cBuffer[RENDERTARGETS]; Pointer zBuffer; Pointer sBuffer; for(int index = 0; index < RENDERTARGETS; index++) { if(state.colorWriteActive(index)) { cBuffer[index] = *Pointer>(data + OFFSET(DrawData,colorBuffer[index])) + yMin * *Pointer(data + OFFSET(DrawData,colorPitchB[index])); } } if(state.depthTestActive) { zBuffer = *Pointer>(data + OFFSET(DrawData,depthBuffer)) + yMin * *Pointer(data + OFFSET(DrawData,depthPitchB)); } if(state.stencilActive) { sBuffer = *Pointer>(data + OFFSET(DrawData,stencilBuffer)) + yMin * *Pointer(data + OFFSET(DrawData,stencilPitchB)); } Int y = yMin; Do { Int x0a = Int(*Pointer(primitive + OFFSET(Primitive,outline->left) + (y + 0) * sizeof(Primitive::Span))); Int x0b = Int(*Pointer(primitive + OFFSET(Primitive,outline->left) + (y + 1) * sizeof(Primitive::Span))); Int x0 = Min(x0a, x0b); for(unsigned int q = 1; q < state.multiSample; q++) { x0a = Int(*Pointer(primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->left) + (y + 0) * sizeof(Primitive::Span))); x0b = Int(*Pointer(primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->left) + (y + 1) * sizeof(Primitive::Span))); x0 = Min(x0, Min(x0a, x0b)); } x0 &= 0xFFFFFFFE; Int x1a = Int(*Pointer(primitive + OFFSET(Primitive,outline->right) + (y + 0) * sizeof(Primitive::Span))); Int x1b = Int(*Pointer(primitive + OFFSET(Primitive,outline->right) + (y + 1) * sizeof(Primitive::Span))); Int x1 = Max(x1a, x1b); for(unsigned int q = 1; q < state.multiSample; q++) { x1a = Int(*Pointer(primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->right) + (y + 0) * sizeof(Primitive::Span))); x1b = Int(*Pointer(primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline->right) + (y + 1) * sizeof(Primitive::Span))); x1 = Max(x1, Max(x1a, x1b)); } Float4 yyyy = Float4(Float(y)) + *Pointer(primitive + OFFSET(Primitive,yQuad), 16); if(interpolateZ()) { for(unsigned int q = 0; q < state.multiSample; q++) { Float4 y = yyyy; if(state.multiSample > 1) { y -= *Pointer(constants + OFFSET(Constants,Y) + q * sizeof(float4)); } Dz[q] = *Pointer(primitive + OFFSET(Primitive,z.C), 16) + y * *Pointer(primitive + OFFSET(Primitive,z.B), 16); } } if(veryEarlyDepthTest && state.multiSample == 1 && !state.depthOverride) { if(!state.stencilActive && state.depthTestActive && (state.depthCompareMode == DEPTH_LESSEQUAL || state.depthCompareMode == DEPTH_LESS)) // FIXME: Both modes ok? { Float4 xxxx = Float4(Float(x0)) + *Pointer(primitive + OFFSET(Primitive,xQuad), 16); Pointer buffer; Int pitch; if(!state.quadLayoutDepthBuffer) { buffer = zBuffer + 4 * x0; pitch = *Pointer(data + OFFSET(DrawData,depthPitchB)); } else { buffer = zBuffer + 8 * x0; } For(Int x = x0, x < x1, x += 2) { Float4 z = interpolate(xxxx, Dz[0], z, primitive + OFFSET(Primitive,z), false, false, state.depthClamp); Float4 zValue; if(!state.quadLayoutDepthBuffer) { // FIXME: Properly optimizes? zValue.xy = *Pointer(buffer); zValue.zw = *Pointer(buffer + pitch - 8); } else { zValue = *Pointer(buffer, 16); } Int4 zTest; if(complementaryDepthBuffer) { zTest = CmpLE(zValue, z); } else { zTest = CmpNLT(zValue, z); } Int zMask = SignMask(zTest); If(zMask == 0) { x0 += 2; } Else { x = x1; } xxxx += Float4(2); if(!state.quadLayoutDepthBuffer) { buffer += 8; } else { buffer += 16; } } } } If(x0 < x1) { if(interpolateW()) { Dw = *Pointer(primitive + OFFSET(Primitive,w.C), 16) + yyyy * *Pointer(primitive + OFFSET(Primitive,w.B), 16); } for(int interpolant = 0; interpolant < MAX_FRAGMENT_INPUTS; interpolant++) { for(int component = 0; component < 4; component++) { if(state.interpolant[interpolant].component & (1 << component)) { Dv[interpolant][component] = *Pointer(primitive + OFFSET(Primitive,V[interpolant][component].C), 16); if(!(state.interpolant[interpolant].flat & (1 << component))) { Dv[interpolant][component] += yyyy * *Pointer(primitive + OFFSET(Primitive,V[interpolant][component].B), 16); } } } } if(state.fog.component) { Df = *Pointer(primitive + OFFSET(Primitive,f.C), 16); if(!state.fog.flat) { Df += yyyy * *Pointer(primitive + OFFSET(Primitive,f.B), 16); } } Short4 xLeft[4]; Short4 xRight[4]; for(unsigned int q = 0; q < state.multiSample; q++) { xLeft[q] = *Pointer(primitive + q * sizeof(Primitive) + OFFSET(Primitive,outline) + y * sizeof(Primitive::Span)); xRight[q] = xLeft[q]; xLeft[q] = Swizzle(xLeft[q], 0xA0) - Short4(1, 2, 1, 2); xRight[q] = Swizzle(xRight[q], 0xF5) - Short4(0, 1, 0, 1); } For(Int x = x0, x < x1, x += 2) { Short4 xxxx = Short4(x); Int cMask[4]; for(unsigned int q = 0; q < state.multiSample; q++) { Short4 mask = CmpGT(xxxx, xLeft[q]) & CmpGT(xRight[q], xxxx); cMask[q] = SignMask(PackSigned(mask, mask)) & 0x0000000F; } quad(cBuffer, zBuffer, sBuffer, cMask, x, y); } } int clusterCount = Renderer::getClusterCount(); for(int index = 0; index < RENDERTARGETS; index++) { if(state.colorWriteActive(index)) { cBuffer[index] += *Pointer(data + OFFSET(DrawData,colorPitchB[index])) << (1 + sw::log2(clusterCount)); // FIXME: Precompute } } if(state.depthTestActive) { zBuffer += *Pointer(data + OFFSET(DrawData,depthPitchB)) << (1 + sw::log2(clusterCount)); // FIXME: Precompute } if(state.stencilActive) { sBuffer += *Pointer(data + OFFSET(DrawData,stencilPitchB)) << (1 + sw::log2(clusterCount)); // FIXME: Precompute } y += 2 * clusterCount; } Until(y >= yMax) } Float4 QuadRasterizer::interpolate(Float4 &x, Float4 &D, Float4 &rhw, Pointer planeEquation, bool flat, bool perspective, bool clamp) { Float4 interpolant = D; if(!flat) { interpolant += x * *Pointer(planeEquation + OFFSET(PlaneEquation, A), 16); if(perspective) { interpolant *= rhw; } } if(clamp) { interpolant = Min(Max(interpolant, Float4(0.0f)), Float4(1.0f)); } return interpolant; } bool QuadRasterizer::interpolateZ() const { return state.depthTestActive || state.pixelFogActive() || (shader && shader->isVPosDeclared() && fullPixelPositionRegister); } bool QuadRasterizer::interpolateW() const { return state.perspective || (shader && shader->isVPosDeclared() && fullPixelPositionRegister); } }