blob: 8c53fca6432d3fc399822839dd8360e40ff5fedc [file] [log] [blame]
/****************************************************************************
* Copyright (C) 2014-2015 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* @file clip.cpp
*
* @brief Implementation for clipping
*
******************************************************************************/
#include <assert.h>
#include "common/os.h"
#include "core/clip.h"
// Temp storage used by the clipper
THREAD SIMDVERTEX_T<SIMD256> tlsTempVertices[7];
#if USE_SIMD16_FRONTEND
THREAD SIMDVERTEX_T<SIMD512> tlsTempVertices_simd16[7];
#endif
float ComputeInterpFactor(float boundaryCoord0, float boundaryCoord1)
{
return (boundaryCoord0 / (boundaryCoord0 - boundaryCoord1));
}
template <SWR_CLIPCODES ClippingPlane>
inline void intersect(
int s, // index to first edge vertex v0 in pInPts.
int p, // index to second edge vertex v1 in pInPts.
const float* pInPts, // array of all the input positions.
const float* pInAttribs, // array of all attributes for all vertex. All the attributes for each
// vertex is contiguous.
int numInAttribs, // number of attributes per vertex.
int i, // output index.
float* pOutPts, // array of output positions. We'll write our new intersection point at i*4.
float* pOutAttribs) // array of output attributes. We'll write our new attributes at
// i*numInAttribs.
{
float t;
// Find the parameter of the intersection.
// t = (v1.w - v1.x) / ((v2.x - v1.x) - (v2.w - v1.w)) for x = w (RIGHT) plane, etc.
const float* v1 = &pInPts[s * 4];
const float* v2 = &pInPts[p * 4];
switch (ClippingPlane)
{
case FRUSTUM_LEFT:
t = ComputeInterpFactor(v1[3] + v1[0], v2[3] + v2[0]);
break;
case FRUSTUM_RIGHT:
t = ComputeInterpFactor(v1[3] - v1[0], v2[3] - v2[0]);
break;
case FRUSTUM_TOP:
t = ComputeInterpFactor(v1[3] + v1[1], v2[3] + v2[1]);
break;
case FRUSTUM_BOTTOM:
t = ComputeInterpFactor(v1[3] - v1[1], v2[3] - v2[1]);
break;
case FRUSTUM_NEAR:
t = ComputeInterpFactor(v1[2], v2[2]);
break;
case FRUSTUM_FAR:
t = ComputeInterpFactor(v1[3] - v1[2], v2[3] - v2[2]);
break;
default:
SWR_INVALID("invalid clipping plane: %d", ClippingPlane);
};
const float* a1 = &pInAttribs[s * numInAttribs];
const float* a2 = &pInAttribs[p * numInAttribs];
float* pOutP = &pOutPts[i * 4];
float* pOutA = &pOutAttribs[i * numInAttribs];
// Interpolate new position.
for (int j = 0; j < 4; ++j)
{
pOutP[j] = v1[j] + (v2[j] - v1[j]) * t;
}
// Interpolate Attributes
for (int attr = 0; attr < numInAttribs; ++attr)
{
pOutA[attr] = a1[attr] + (a2[attr] - a1[attr]) * t;
}
}
// Checks whether vertex v lies inside clipping plane
// in homogenous coords check -w < {x,y,z} < w;
//
template <SWR_CLIPCODES ClippingPlane>
inline int inside(const float v[4])
{
switch (ClippingPlane)
{
case FRUSTUM_LEFT:
return (v[0] >= -v[3]);
case FRUSTUM_RIGHT:
return (v[0] <= v[3]);
case FRUSTUM_TOP:
return (v[1] >= -v[3]);
case FRUSTUM_BOTTOM:
return (v[1] <= v[3]);
case FRUSTUM_NEAR:
return (v[2] >= 0.0f);
case FRUSTUM_FAR:
return (v[2] <= v[3]);
default:
SWR_INVALID("invalid clipping plane: %d", ClippingPlane);
return 0;
}
}
// Clips a polygon in homogenous coordinates to a particular clipping plane.
// Takes in vertices of the polygon (InPts) and the clipping plane
// Puts the vertices of the clipped polygon in OutPts
// Returns number of points in clipped polygon
//
template <SWR_CLIPCODES ClippingPlane>
int ClipTriToPlane(const float* pInPts,
int numInPts,
const float* pInAttribs,
int numInAttribs,
float* pOutPts,
float* pOutAttribs)
{
int i = 0; // index number of OutPts, # of vertices in OutPts = i div 4;
for (int j = 0; j < numInPts; ++j)
{
int s = j;
int p = (j + 1) % numInPts;
int s_in = inside<ClippingPlane>(&pInPts[s * 4]);
int p_in = inside<ClippingPlane>(&pInPts[p * 4]);
// test if vertex is to be added to output vertices
if (s_in != p_in) // edge crosses clipping plane
{
// find point of intersection
intersect<ClippingPlane>(
s, p, pInPts, pInAttribs, numInAttribs, i, pOutPts, pOutAttribs);
i++;
}
if (p_in) // 2nd vertex is inside clipping volume, add it to output
{
// Copy 2nd vertex position of edge over to output.
for (int k = 0; k < 4; ++k)
{
pOutPts[i * 4 + k] = pInPts[p * 4 + k];
}
// Copy 2nd vertex attributes of edge over to output.
for (int attr = 0; attr < numInAttribs; ++attr)
{
pOutAttribs[i * numInAttribs + attr] = pInAttribs[p * numInAttribs + attr];
}
i++;
}
// edge does not cross clipping plane and vertex outside clipping volume
// => do not add vertex
}
return i;
}
void ClipRectangles(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simdvector prims[],
uint32_t primMask,
simdscalari const& primId,
simdscalari const& viewportIdx,
simdscalari const& rtIdx)
{
RDTSC_BEGIN(FEClipRectangles, pDC->drawId);
Clipper<SIMD256, 3> clipper(workerId, pDC);
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipRectangles, 1);
}
void ClipTriangles(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simdvector prims[],
uint32_t primMask,
simdscalari const& primId,
simdscalari const& viewportIdx,
simdscalari const& rtIdx)
{
RDTSC_BEGIN(FEClipTriangles, pDC->drawId);
Clipper<SIMD256, 3> clipper(workerId, pDC);
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipTriangles, 1);
}
void ClipLines(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simdvector prims[],
uint32_t primMask,
simdscalari const& primId,
simdscalari const& viewportIdx,
simdscalari const& rtIdx)
{
RDTSC_BEGIN(FEClipLines, pDC->drawId);
Clipper<SIMD256, 2> clipper(workerId, pDC);
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipLines, 1);
}
void ClipPoints(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simdvector prims[],
uint32_t primMask,
simdscalari const& primId,
simdscalari const& viewportIdx,
simdscalari const& rtIdx)
{
RDTSC_BEGIN(FEClipPoints, pDC->drawId);
Clipper<SIMD256, 1> clipper(workerId, pDC);
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipPoints, 1);
}
#if USE_SIMD16_FRONTEND
void SIMDCALL ClipRectangles_simd16(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simd16vector prims[],
uint32_t primMask,
simd16scalari const& primId,
simd16scalari const& viewportIdx,
simd16scalari const& rtIdx)
{
RDTSC_BEGIN(FEClipRectangles, pDC->drawId);
enum
{
VERTS_PER_PRIM = 3
};
Clipper<SIMD512, VERTS_PER_PRIM> clipper(workerId, pDC);
pa.useAlternateOffset = false;
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipRectangles, 1);
}
void SIMDCALL ClipTriangles_simd16(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simd16vector prims[],
uint32_t primMask,
simd16scalari const& primId,
simd16scalari const& viewportIdx,
simd16scalari const& rtIdx)
{
RDTSC_BEGIN(FEClipTriangles, pDC->drawId);
enum
{
VERTS_PER_PRIM = 3
};
Clipper<SIMD512, VERTS_PER_PRIM> clipper(workerId, pDC);
pa.useAlternateOffset = false;
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipTriangles, 1);
}
void SIMDCALL ClipLines_simd16(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simd16vector prims[],
uint32_t primMask,
simd16scalari const& primId,
simd16scalari const& viewportIdx,
simd16scalari const& rtIdx)
{
RDTSC_BEGIN(FEClipLines, pDC->drawId);
enum
{
VERTS_PER_PRIM = 2
};
Clipper<SIMD512, VERTS_PER_PRIM> clipper(workerId, pDC);
pa.useAlternateOffset = false;
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipLines, 1);
}
void SIMDCALL ClipPoints_simd16(DRAW_CONTEXT* pDC,
PA_STATE& pa,
uint32_t workerId,
simd16vector prims[],
uint32_t primMask,
simd16scalari const& primId,
simd16scalari const& viewportIdx,
simd16scalari const& rtIdx)
{
RDTSC_BEGIN(FEClipPoints, pDC->drawId);
enum
{
VERTS_PER_PRIM = 1
};
Clipper<SIMD512, VERTS_PER_PRIM> clipper(workerId, pDC);
pa.useAlternateOffset = false;
clipper.ExecuteStage(pa, prims, primMask, primId, viewportIdx, rtIdx);
RDTSC_END(FEClipPoints, 1);
}
#endif