From 1d4f9a5bbfaf1eb3157aa84b01cd3a741cb0f3bd Mon Sep 17 00:00:00 2001 From: Wenli Zhao Date: Sun, 15 Oct 2017 22:54:33 -0400 Subject: [PATCH 1/6] early comments --- src/rasterize.cu | 49 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/rasterize.cu b/src/rasterize.cu index 1262a09..f5129ea 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -62,10 +62,10 @@ namespace { // The attributes listed below might be useful, // but always feel free to modify on your own - // glm::vec3 eyePos; // eye space position used for shading - // glm::vec3 eyeNor; - // VertexAttributeTexcoord texcoord0; - // TextureData* dev_diffuseTex; + glm::vec3 eyePos; // eye space position used for shading + glm::vec3 eyeNor; + VertexAttributeTexcoord texcoord0; + TextureData* dev_diffuseTex; // ... }; @@ -294,6 +294,7 @@ void traverseNode ( } } +// Called once in main init function. void rasterizeSetBuffers(const tinygltf::Scene & scene) { totalNumPrimitives = 0; @@ -331,7 +332,7 @@ void rasterizeSetBuffers(const tinygltf::Scene & scene) { // 2. for each mesh: // for each primitive: - // build device buffer of indices, materail, and each attributes + // build device buffer of indices, material, and each attributes // and store these pointers in a map { @@ -638,9 +639,18 @@ void _vertexTransformAndAssembly( // Multiply the MVP matrix for each vertex position, this will transform everything into clipping space // Then divide the pos by its w element to transform into NDC space // Finally transform x and y to viewport space + VertexIndex vIndex = primitive.dev_indices[vid]; + VertexAttributePosition vPos = primitive.dev_position[vIndex]; + VertexAttributeNormal vNormal = primitive.dev_normal[vIndex]; + VertexAttributeTexcoord vTexcoord = primitive.dev_texcoord0[vIndex]; + + // Note to self: This should be in NDC. + VertexOut vOut; + vOut.pos = glm::vec4(vPos.x, vPos.y, vPos.z, 1); + primitive.dev_verticesOut[vid] = vOut; // TODO: Apply vertex assembly here - // Assemble all attribute arraies into the primitive array + // Assemble all attribute arrays into the primitive array } } @@ -660,12 +670,15 @@ void _primitiveAssembly(int numIndices, int curPrimitiveBeginId, Primitive* dev_ // TODO: uncomment the following code for a start // This is primitive assembly for triangles - //int pid; // id for cur primitives vector - //if (primitive.primitiveMode == TINYGLTF_MODE_TRIANGLES) { - // pid = iid / (int)primitive.primitiveType; - // dev_primitives[pid + curPrimitiveBeginId].v[iid % (int)primitive.primitiveType] - // = primitive.dev_verticesOut[primitive.dev_indices[iid]]; - //} + int pid; // id for cur primitives vector + if (primitive.primitiveMode == TINYGLTF_MODE_TRIANGLES) { + // id divided by 3 for triangles + pid = iid / (int)primitive.primitiveType; + + // every primitive has a vertex, + dev_primitives[pid + curPrimitiveBeginId].v[iid % (int)primitive.primitiveType] + = primitive.dev_verticesOut[primitive.dev_indices[iid]]; + } // TODO: other primitive types (point, line) @@ -673,6 +686,11 @@ void _primitiveAssembly(int numIndices, int curPrimitiveBeginId, Primitive* dev_ } +__global__ +void _rasterizeTriangles(int numPrimitives, Fragment* dev_fragments, Primitive* dev_primitives) { + +} + /** @@ -702,9 +720,12 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g dim3 numBlocksForVertices((p->numVertices + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); dim3 numBlocksForIndices((p->numIndices + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); + // 1. Vertex Assembly _vertexTransformAndAssembly << < numBlocksForVertices, numThreadsPerBlock >> >(p->numVertices, *p, MVP, MV, MV_normal, width, height); checkCUDAError("Vertex Processing"); cudaDeviceSynchronize(); + + // 2. Primitive Assembly _primitiveAssembly << < numBlocksForIndices, numThreadsPerBlock >> > (p->numIndices, curPrimitiveBeginId, @@ -723,7 +744,9 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g initDepth << > >(width, height, dev_depth); // TODO: rasterize - + dim3 numThreadsPerBlock(128); + dim3 numBlocksForPrimitives((curPrimitiveBeginId + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); + // _rasterizeTriangle << < numBlocksForPrimitives, numThreadsPerBlock >> > (); // Copy depthbuffer colors into framebuffer From e4caa9e4e43d95e5a1093f9336480e098656196b Mon Sep 17 00:00:00 2001 From: Wenli Zhao Date: Mon, 16 Oct 2017 23:18:42 -0400 Subject: [PATCH 2/6] triangles appear --- src/rasterize.cu | 80 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 7 deletions(-) diff --git a/src/rasterize.cu b/src/rasterize.cu index f5129ea..ea9a75e 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -640,13 +640,26 @@ void _vertexTransformAndAssembly( // Then divide the pos by its w element to transform into NDC space // Finally transform x and y to viewport space VertexIndex vIndex = primitive.dev_indices[vid]; - VertexAttributePosition vPos = primitive.dev_position[vIndex]; - VertexAttributeNormal vNormal = primitive.dev_normal[vIndex]; - VertexAttributeTexcoord vTexcoord = primitive.dev_texcoord0[vIndex]; + VertexAttributePosition vPos = primitive.dev_position[vid]; + VertexAttributeNormal vNormal = primitive.dev_normal[vid]; + VertexAttributeTexcoord vTexcoord = primitive.dev_texcoord0[vid]; + + // NDC + glm::vec4 vOutPos = MVP * glm::vec4(vPos, 1.0f); + vOutPos = vOutPos / vOutPos.w; + + // Screen Space + vOutPos = glm::vec4(0.5f * (float) width * (vOutPos.x + 1.0f), 0.5f * (float) height * (1.0f - vOutPos.y), vOutPos.z, 1.0f); + + glm::vec3 eyePos = glm::vec3(MV * glm::vec4(vPos, 0)); - // Note to self: This should be in NDC. VertexOut vOut; - vOut.pos = glm::vec4(vPos.x, vPos.y, vPos.z, 1); + // vOut.pos = glm::vec4(vPos.x, vPos.y, vPos.z, 1); + vOut.pos = vOutPos; + vOut.eyeNor = glm::vec3(MV * glm::vec4(vNormal,0.0f)); + vOut.texcoord0 = vTexcoord; + vOut.eyePos = eyePos; + primitive.dev_verticesOut[vid] = vOut; // TODO: Apply vertex assembly here @@ -686,13 +699,66 @@ void _primitiveAssembly(int numIndices, int curPrimitiveBeginId, Primitive* dev_ } +__device__ +glm::vec3 barycentricInterpolation(const glm::vec3 tri[3], const glm::vec3 coord) { + return coord.x * tri[0] + coord.y * tri[1] + coord.z * tri[2]; +} + __global__ -void _rasterizeTriangles(int numPrimitives, Fragment* dev_fragments, Primitive* dev_primitives) { +void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragment* dev_fragments, Primitive* dev_primitives, int* dev_depth) { + int iid = (blockIdx.x * blockDim.x) + threadIdx.x; + + if (iid < numPrimitives) { + Primitive triangle = dev_primitives[iid]; + glm::vec3 tri[3] = { glm::vec3(triangle.v[0].pos), + glm::vec3(triangle.v[1].pos), + glm::vec3(triangle.v[2].pos) }; + AABB boundingBox = getAABBForTriangle(tri); + + for (int y = boundingBox.min.y; y < boundingBox.max.y; y++) { + for (int x = boundingBox.min.x; x < boundingBox.max.x; x++) { + Fragment f; + glm::vec3 bary = calculateBarycentricCoordinate(tri, glm::vec2((float)x, (float)y)); + if (isBarycentricCoordInBounds(bary)) { + + + + f.color = glm::vec3(1, 0, 1); + // glm::vec3 uuh[3] = { glm::vec3(1,1,1) , glm::vec3(1,0,1) , glm::vec3(1,0,1) }; + //f.color = barycentricInterpolation(uuh, bary); + + glm::vec3 eyePos[3] = { triangle.v[0].eyePos, triangle.v[1].eyePos, triangle.v[2].eyePos }; + f.eyePos = barycentricInterpolation(eyePos, bary); + + glm::vec3 eyeNormals[3] = { triangle.v[0].eyeNor, triangle.v[1].eyeNor, triangle.v[2].eyeNor }; + f.eyeNor = barycentricInterpolation(eyeNormals, bary); + glm::vec3 pos = barycentricInterpolation(tri, bary); + + int old = dev_depth[y*width + x]; + + + atomicMin(&dev_depth[y*width + x], (int)( pos.z * INT_MAX)); + + if (old != dev_depth[y*width + x]) { + f.color = barycentricInterpolation(eyeNormals, bary); + //f.color = glm::vec3(1, 1, 1); + } + + + f.texcoord0 = triangle.v[0].texcoord0; + f.dev_diffuseTex = triangle.v[0].dev_diffuseTex; + dev_fragments[y * width + x] = f; + } + } + } + } } + + /** * Perform rasterization. */ @@ -746,7 +812,7 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g // TODO: rasterize dim3 numThreadsPerBlock(128); dim3 numBlocksForPrimitives((curPrimitiveBeginId + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); - // _rasterizeTriangle << < numBlocksForPrimitives, numThreadsPerBlock >> > (); + _rasterizeTriangles << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth); // Copy depthbuffer colors into framebuffer From f9a564e78d6440a2a4ea153443f2336d13b5fe1d Mon Sep 17 00:00:00 2001 From: Wenli Zhao Date: Tue, 17 Oct 2017 22:27:04 -0400 Subject: [PATCH 3/6] depth buffering --- renders/Capture.PNG | Bin 0 -> 55313 bytes renders/Capture2.PNG | Bin 0 -> 22102 bytes src/main.cpp | 2 + src/rasterize.cu | 124 +++++++++++++++++++++++++++++++++++-------- 4 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 renders/Capture.PNG create mode 100644 renders/Capture2.PNG diff --git a/renders/Capture.PNG b/renders/Capture.PNG new file mode 100644 index 0000000000000000000000000000000000000000..b6ad63d8559a7eb57dd9dee3c95dddaa24f1f743 GIT binary patch literal 55313 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 AQ2+n{ literal 0 HcmV?d00001 diff --git a/src/main.cpp b/src/main.cpp index 7986959..aed3732 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -108,6 +108,8 @@ void runCuda() { scale * ((float)width / (float)height), -scale, scale, 1.0, 1000.0); + P = glm::perspective(45.0f, scale*(float)width / (float)height, 1.0f, 1000.0f); + glm::mat4 V = glm::mat4(1.0f); glm::mat4 M = diff --git a/src/rasterize.cu b/src/rasterize.cu index ea9a75e..abb7fb6 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -18,6 +18,11 @@ #include #include +#define ATOMIC 1 +#define POINT 0 +#define LINE 0 +#define TRIANGLE 1 + namespace { typedef unsigned short VertexIndex; @@ -46,7 +51,7 @@ namespace { // glm::vec3 col; glm::vec2 texcoord0; TextureData* dev_diffuseTex = NULL; - // int texWidth, texHeight; + int texWidth, texHeight; // ... }; @@ -66,7 +71,7 @@ namespace { glm::vec3 eyeNor; VertexAttributeTexcoord texcoord0; TextureData* dev_diffuseTex; - // ... + int texWidth, texHeight; }; struct PrimitiveDevBufPointers { @@ -94,6 +99,7 @@ namespace { VertexOut* dev_verticesOut; // TODO: add more attributes when needed + }; } @@ -110,6 +116,7 @@ static Fragment *dev_fragmentBuffer = NULL; static glm::vec3 *dev_framebuffer = NULL; static int * dev_depth = NULL; // you might need this buffer when doing depth test +static unsigned int * dev_mutex = NULL; /** * Kernel that writes the image to the OpenGL PBO directly. @@ -133,6 +140,16 @@ void sendImageToPBO(uchar4 *pbo, int w, int h, glm::vec3 *image) { } } +__device__ +glm::vec3 getColor(TextureData* dev_texcoord0, int u, int v, int width) { + + int index = u + v*width; + float r = (float) dev_texcoord0[index * 3] / 255.0f; + float g = (float) dev_texcoord0[index * 3 + 1] / 255.0f; + float b = (float) dev_texcoord0[index * 3 + 2] / 255.0f; + return glm::vec3(r, g, b); +} + /** * Writes fragment colors to the framebuffer */ @@ -146,8 +163,38 @@ void render(int w, int h, Fragment *fragmentBuffer, glm::vec3 *framebuffer) { framebuffer[index] = fragmentBuffer[index].color; // TODO: add your fragment shader code here + Fragment frag = fragmentBuffer[index]; + + glm::vec3 lightPos = glm::vec3(0.0f, 5.0f, 0.0f); + glm::vec3 ambientCol = frag.color; + + if (frag.color != glm::vec3(0.0, 0.0, 0.0)) { + //ambientCol = getColor(frag.dev_diffuseTex, frag.texcoord0.x * frag.texWidth, frag.texHeight * frag.texHeight, frag.texWidth); + } + + glm::vec3 diffuseCol = glm::vec3(0.5f, 0.0f, 0.0f); + glm::vec3 specColor = glm::vec3(1.0f, 1.0f, 1.0f); + const float shininess = 16.0; + const float screenGamma = 2.2; + + glm::vec3 lightDir = normalize(lightPos - fragmentBuffer[index].eyePos); + glm::vec3 normal = fragmentBuffer[index].eyeNor; + float lambertian = max(dot(lightDir, normal), 0.0f); + float specular = 0.0; + if (lambertian > 0.0) { + glm::vec3 viewDir = normalize(-fragmentBuffer[index].eyePos); + + glm::vec3 halfDir = normalize(lightDir + viewDir); + float specAngle = max(dot(halfDir, normal), 0.0f); + specular = pow(specAngle, shininess); + } + glm::vec3 colorLinear = ambientCol + lambertian * diffuseCol + specular*specColor; + + glm::vec3 colorGammaCorrected = pow(colorLinear, glm::vec3(1.0f / screenGamma)); + framebuffer[index] = colorGammaCorrected; } + } /** @@ -166,11 +213,14 @@ void rasterizeInit(int w, int h) { cudaFree(dev_depth); cudaMalloc(&dev_depth, width * height * sizeof(int)); + cudaFree(dev_mutex); + cudaMalloc(&dev_mutex, width*height * sizeof(unsigned int)); + checkCUDAError("rasterizeInit"); } __global__ -void initDepth(int w, int h, int * depth) +void initDepth(int w, int h, int * depth, unsigned int * mutex) { int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; @@ -179,6 +229,7 @@ void initDepth(int w, int h, int * depth) { int index = x + (y * w); depth[index] = INT_MAX; + mutex[index] = 0; } } @@ -659,6 +710,8 @@ void _vertexTransformAndAssembly( vOut.eyeNor = glm::vec3(MV * glm::vec4(vNormal,0.0f)); vOut.texcoord0 = vTexcoord; vOut.eyePos = eyePos; + vOut.texHeight = primitive.diffuseTexHeight; + vOut.texWidth = primitive.diffuseTexWidth; primitive.dev_verticesOut[vid] = vOut; @@ -704,8 +757,13 @@ glm::vec3 barycentricInterpolation(const glm::vec3 tri[3], const glm::vec3 coord return coord.x * tri[0] + coord.y * tri[1] + coord.z * tri[2]; } +__device__ +glm::vec2 perspectiveInterp(const glm::vec2 texcoord[3], const glm::vec3 coord) { + return (float) coord.x * texcoord[0] + (float) coord.y * texcoord[1] + (float) coord.z * texcoord[2]; +} + __global__ -void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragment* dev_fragments, Primitive* dev_primitives, int* dev_depth) { +void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragment* dev_fragments, Primitive* dev_primitives, int* dev_depth, unsigned int * dev_mutex) { int iid = (blockIdx.x * blockDim.x) + threadIdx.x; if (iid < numPrimitives) { @@ -720,35 +778,52 @@ void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragmen Fragment f; glm::vec3 bary = calculateBarycentricCoordinate(tri, glm::vec2((float)x, (float)y)); if (isBarycentricCoordInBounds(bary)) { - - - - f.color = glm::vec3(1, 0, 1); - // glm::vec3 uuh[3] = { glm::vec3(1,1,1) , glm::vec3(1,0,1) , glm::vec3(1,0,1) }; - //f.color = barycentricInterpolation(uuh, bary); - + // eyePos glm::vec3 eyePos[3] = { triangle.v[0].eyePos, triangle.v[1].eyePos, triangle.v[2].eyePos }; f.eyePos = barycentricInterpolation(eyePos, bary); + // eyeNormals glm::vec3 eyeNormals[3] = { triangle.v[0].eyeNor, triangle.v[1].eyeNor, triangle.v[2].eyeNor }; f.eyeNor = barycentricInterpolation(eyeNormals, bary); + // pos glm::vec3 pos = barycentricInterpolation(tri, bary); - int old = dev_depth[y*width + x]; - + // textures: + // TODO Perspective correction + glm::vec2 texCoord[3] = { triangle.v[0].texcoord0, triangle.v[1].texcoord0, triangle.v[2].texcoord0 }; + glm::vec2 texCoordinate = glm::vec2(perspectiveInterp(texCoord, bary)); - atomicMin(&dev_depth[y*width + x], (int)( pos.z * INT_MAX)); + f.texcoord0 = glm::vec2(texCoordinate.x*triangle.v[0].texWidth, texCoordinate.y * triangle.v[0].texHeight); - if (old != dev_depth[y*width + x]) { - f.color = barycentricInterpolation(eyeNormals, bary); - //f.color = glm::vec3(1, 1, 1); - } + //f.texcoord0.x *= triangle.v[0].texWidth; + //f.texcoord0.y *= triangle.v[0].texHeight; + + f.color = glm::vec3(0.3f, 0.0f, 0.3f); + f.dev_diffuseTex = triangle.v[0].dev_diffuseTex; + f.texWidth = triangle.v[0].texWidth; + f.texHeight = triangle.v[0].texHeight; + + // Depth Buffering + int old = dev_depth[y*width + x]; + bool isSet; + do { + isSet = (atomicCAS(&dev_mutex[y*width + x], 0, 1) == 0); + if (isSet) { + // Critical section goes here. + // The critical section MUST be inside the wait loop; + // if it is afterward, a deadlock will occur. + dev_depth[y*width + x] = min(old, (int)(pos.z * INT_MAX)); + if (old > dev_depth[y*width + x]) { + dev_fragments[y * width + x] = f; + } + } + if (isSet) { + dev_mutex[y*width + x] = 0; + } + } while (!isSet); - f.texcoord0 = triangle.v[0].texcoord0; - f.dev_diffuseTex = triangle.v[0].dev_diffuseTex; - dev_fragments[y * width + x] = f; } } } @@ -807,12 +882,12 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g } cudaMemset(dev_fragmentBuffer, 0, width * height * sizeof(Fragment)); - initDepth << > >(width, height, dev_depth); + initDepth << > >(width, height, dev_depth, dev_mutex); // TODO: rasterize dim3 numThreadsPerBlock(128); dim3 numBlocksForPrimitives((curPrimitiveBeginId + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); - _rasterizeTriangles << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth); + _rasterizeTriangles << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); // Copy depthbuffer colors into framebuffer @@ -861,5 +936,8 @@ void rasterizeFree() { cudaFree(dev_depth); dev_depth = NULL; + cudaFree(dev_mutex); + dev_mutex = NULL; + checkCUDAError("rasterize Free"); } From 21f410b3d249642e43ee25bd28743e2811f33a0a Mon Sep 17 00:00:00 2001 From: Wenli Zhao Date: Wed, 18 Oct 2017 22:17:29 -0400 Subject: [PATCH 4/6] texturing and point and line rasterization --- renders/Capture3.PNG | Bin 0 -> 15071 bytes renders/lines.PNG | Bin 0 -> 23797 bytes renders/points.PNG | Bin 0 -> 9734 bytes src/rasterize.cu | 115 +++++++++++++++++++++++++++++++++++-------- 4 files changed, 94 insertions(+), 21 deletions(-) create mode 100644 renders/Capture3.PNG create mode 100644 renders/lines.PNG create mode 100644 renders/points.PNG diff --git a/renders/Capture3.PNG b/renders/Capture3.PNG new file mode 100644 index 0000000000000000000000000000000000000000..043767fff094febbca7847f913da4c4cba4d21bd GIT binary patch literal 15071 zcmeHu_g|CQ(`X1KbVQnq5X1sXR|z6b5mAZ(TM9@CHiQVog@6R`6?nt;GP@%!HQ-hbf!bl)EcpQoI8X68(vISECMEH~Kat>zXHP+B-5N9CLd@3|X$yf=rpf&95eL^&1P8ZZ z2t>X^_$Sg8RC*l(u?TTIZF~8ymtagPofzb)yCQPhc89XP#|1Il9T&t@((O;Ti4z7L zuUFSNL)2!A#2TK`{hZ_?7-}H?b?9!u;Mke9Db{U6{X1Kk1 zyU1L%VK3%w*KY_`nPpp{yWoesZhSshzN~$TWSO=deY+);GQtZ`ULj1+^$3tfp#IR*p zF`Aq7ethOuRE)|4`^l`ruXmjKw#6pjbnc~}J#;;N8v{9eP&HQnNxRsz^R`{gKE)K4 ziep>sJI8I;n0-4^Se_2Hv7h_4cTL8C6(^-7JaU&#z|2opN{$vNOAMtgZNtp>R7!eW zwD=xu-8U;jfLv8%q=wL^Zx#;1CM7!e5*~#RrcDY5WhNzF?cGr*YLR@PIS?{vpc-py zaX)ydZ&s3kysCJs&o=wx?_QV~>lAzQ@R^hBJ5CkGEO_VM9BK$*>U+_kI?nZ~qRT~# zgVpdE1Z*fCn~?Fl{3|MkqyX_K02hztTd3Y7V~EFNYy!s_=HcQ@@`iZCViQo#Fn5M09C`;Ed?CDwt?y&BCStOU!);~2=(9VvvRzP6q7mq|e)qh}1- zFF3;-v3kv25F_xUrmszL{tPK!#AA;t?^aR#zR~g}FH!Te;58?hJwtEC8n)xrUX9!k zlLX3>@d(J#O3AYaG{t9<~@WrB?U8WYgF-Yo5IeLJy>=Tx|=L+HDz zDDP$Qrktx8Z55Wa^~0`sCJk_+%T~(nLZtcI(8KR8!r4qywWuF2 zlNWTFWUw2*k5gEV!Vgj8Bs;oF>RJ~Y*wtAj2v@(n0jriW8fRbjDt??9P6%$Dn%fQ@ zKg(|0Nni25mk-s|SLNY~M2Gd}Y`liHUc2ILio#tMAFzjNNw*gZkPGh3zKg6W8}|2T z(#XhoUBs(zA1jdkS~m1e8=k-S>p_UQTcspSU$gho`25FC!NSIGQ)_J9V~G9Vm!`_t z=7Z!$^uomDL2{DVM6KgCrQ-X;iXrQNzkmCC#S$4fQL^L?(LJEb+fyX^L9ZsQ$1i#! zCCfF)-{I@KywxUTU{g+niTO(KdnQ87EYil*yIg(~f zhGGgKz0Y=TDAIO=X;Z&OojN)j)by&${PAX!c3Z<08?#xjv2`m3X@&@KIc3n^<_N2} z7S@yE-6VxU>>rxG;yLv(a%9tg?}i{rY&vkwq%3lw4-d&nz$V0J$a{6s;yBaCB3n4o zU*DXa|GlSE%hi81!hyMcBT4LR{XI#{;NE6=79S|p9|(!q)~z-zt4N=X5j~IPHFSUe z_L|X}$B*~PVha<6+k^JqHVG8`V=qzM^3}&G*;{ETMfnYWcv-0Tz!r_~k(%+Ll_5@h zcWX-@3#m4!!H_yV4Jbmi!MHEbRhkfOTq}~-TVxma8Br0=UTJF&zIvi>7D9D5 zs5)}U!0<6VVuHJiy7lV@)4zqYi{}4J5}d{-#pU-lO+HS`v8fu1y1S^2G;AXrvy00m z5I2Qu(FRp}5A7c-Uy4|{QSM2}dNbamOuey-#2~*Lx2i6im5MsoZydhZ29}+-i(B9p zZgXxFO}~mN8Wh2nW3L~$Xws-RvnuFNuZYJiQX7?N{HtuO!GUEltqH5fGUxGudldIL zpP6*r(>$e(OfML&_UhwIhk`G9MHAs1?ob2yJgOu1b10AO?fO+Td({tM&NQ8gCjR2R z_1PPque9;hO97V&813M5%e!x(Rl0u)+A%AGDN3feCl#pfK=SyG?2lPz5s2rTK1g=G z(>CQDsmpR)F<;@omp*H$O8h-_BQVJBV59#`_-JZGA|)try!YPO#i^;Y*}O^OInp3m zry9c`J5O9@kOD99_+{*~h_nFs2dh8J*3eIzpG=1L1@lOSgQD0X>~(Ro0{#KRoTg7( zBO`ce>;dci1KsVMcf-@(oTfj^VwTr)wfrBM;!q4SkJTb;mq<}FRiWj*w<-$1ddXLs zdwnG5e+`;W4BVUTu15soRUOV)0+?Jsa3xL|U`UN}dnQj)2$5c^vEQbn3Zd zv^i=>wp{+b*uqVPKJVw%e=lIskUg7~l|nr2NtM3LDd)HGFJ-}LHg#nPn*Wgqc0F0U zZ3Ap}*e^4y!AJXMMX62(zkV_k;b$t~$2W3YrkaaqC==JRTKKUGve?0)&WAlmM;9*Y z;ZVKgaBSo=`ehhJr)k?kN!~xXSV26>|56*UZ~6U&1eCK$;WqC^;RKuQSfNPQt91e7>IbP%PJd`U;(4>`4gt@9=6T#q*qvQ{ zv*OeMv?BxJCnv@ zIQQ)zjTS4R+RC5<^)m3Q3vh9a)%kpSs$Tm$!V^SU|PIb?0=GK!5D4F|c26LPz)V~y|HF2t|D{z*>A#ZT+Q85DvtNS!` z=0xzam?G{g66%sOA|ZaXpsaw^n1>UmoIR#B3{1hqlr}p)D{ItCdp3$W5{B=)c8Aet zCIi@41g|CeB|_5*Z#2RIn&6XM2c#uo=5Y{b9Qy{4BL{JpY`2K=^si8(d@%!)bYPHvRbxK z#L6iViUpRpCrozz)yk6fqf5hqv8em@Xk74_N&FSYda)|4rM8_D*o|87K-KeM`IT~* z6F+kN)*riO6>CM#n{KkF1MDzFrvI%<)qR_MSUvq>##q{Z+_H8%oaQxtnW0y4yFFH( zcICeT*8#5aPX%-<-}Wg>+5}3vN>-5B>NWD%{G#jHpBBkC-F#Jo?01cPZMylXBxnH> zTuDwr&0a;Z$Va6vy*R!<@<9?Gx7>ia#*&6vFarIU;%IGEw^+6Xy7tqlvUHTv$n2st z7E!s$%s+yh*sk$h<+}m9aANC+-}+2XPI3Nrjvr}uIzSX7Ud2z~SW(sYHj%3(^~H+T zQC~zTVRStYB2*Q&C!n6C_iC?xB7c{V+ZQUM0pf%Mb~p$c_TvP?6a# zZ+dPtDwpcL1;8fui~#(Q*_=@!BdtA_5p)vl-Pb)oiG819kG@`A2ZT*sm5P@Oq#gQB z_X~cTeKCWBf1Bjq);xvVET0bO*){t8lRz-B{)cBTY0K;uhu{O0uDC!|9a%7y{+kG1 zLukItC)aN=dsmwmPI zvRLDxBx-%r*Sk=zmB+FXI+5xws;{v$X;B!UYEG(r^YC`JG*$fcta?1c0BaYkQtFRg z_&feeufKmOU8fndXXAnDpZ-@P6x=xPf%@0NTY%W4)k|SvEvJEN1!jV9V@u`O!GLO( zkkXr^j~R6`54eRZ?%QMwl*)bnUN-T{;7%%FIYm{je1qd8Q28_J-~RDms=6;9o6V?K znxLd`M7agtUmEhQhdMIXFr)OEX6RXCRk!EtBhrWxa^ppn1mKP8+Q>9bZ1*Xy5w7{q z$ks*=qIJ9b2EW9cA-IT2=jT$%gN3VEKfHV>@cL83+Ayj*++cAYm8dV0vOB#FGx?=+ zuYOI#C=z*lBBTOdnHz-Crv)X%pcbq2OgO*F2a&j@n{z28Gls^)Mm^{4l2mG5H@I;+ z`M!#95-Tg;8cSl3ZYase(G~ozh(Gc&sJfWFhCx_i-yIqFL6$ycY^{q6nDVKGplzv7 ze*GR>5`YP)KvYB(i-}|XB@G5gK!)<^ixVkJpL(GRV_!2;KwK!tB~ELdbr%d&f&j1 zNIe3&x2H=<(k}hW0kjiCr_hE5?f{k%hfS`nHnU5BY0&-e6PixDC}5gXROFKgnSEx` zLgnZz_Fj9}za;890r*6z9{dm=xy8}J$$3(*BuRy7Q@VA2Bq|uRBpxKiNKM!u{zH+H)>k zsmdm7ca6VDf8#=d1QkvLRy-L)NQKv|PZvS|y7`8_dCze9>+7^(S~Rdm(eu@Hc8{~=xr$;`o3=U-UP!+f+_1h=9#XAM=4Yxj?AXA9OZBTi#|q3G$E%!OvbY1Dmk%8?)_cSn_3Zu!{s zp~Ald&=Jx9m?DFQwjQzF5@3z;==@2W1)K_?&0*vKVF1u}bhC4tA%k`O5K3R)`!f4D zR)y|Px0t<}s!fT^gF5|M=f!!S`r^N74C~-3Kjr)#=Bo?`g zl43Uq*waOUSGS*Af1Z85rzks&PGU43z_lImvlIh5`fI!UzaQikqZYaX2HVJv^R@D5 z;&U^lv1B8(w2oR?{+Jkb#axB%RKCl5(3msQr$b#fe+C{!*+GzJKy1l>B1#LV>S4S4Ak*k%w! z5|N3NV+bBgsy?I6QfP;Ao)<5Sc^&(T1io@X-RS8hPimGvN@*MqvWP2(=%X&|Y6}^x z!jJ^jU5Ns(NK&kbfTN{RW9C-o3fTX^IWB}V`ff@+wl-@+!6q`RW${{_HpRki;>Q;O z!3%k>Lgsjo>Ynm&H-%C8wE&Crt9Y_A%GQ7S$;tkfD94R0=aEe>E|jAWukj3~SX@Ue zVNY0&N9SKGbyxafZ2+zWXQy1iZY5AvMB!&}@l16wc7#sU(&*p(@ zxcdt-v7UT1)J$PE2N$X`Wvk~nMuF4D`w~PC=I91o5#q|&*WVL8AL@lJPeXMiO?-Rb zzhs#9ycpBEU3ZOmq27O>!`b^1d9*)j{xjQ98^8K&=I}h%>RhT>Tad3Tra9t(#~oN- zofs9AU^KH^1XBG=AB~5MCeF`ZYu>suQcIaH>>m*Q+l{VnV_a*o-V^O2b0lq|TQF>3 zMe5YXgFWw-!35ooDpaI13Tre)D4@RBWtK}`*huhOf36mgEQ!BMx4;}?<@m~)Tq{*a zJu4fLHl5fQ5V)lvboH&rbJgtzJQPs-cn_KBb^Ac{r8qydWT<5mK(oi%#StB|8_SPM zT)Ka}$EtT=v^Y=}^U~dL6GU%D3Kzzx((c*s7G-@87EfgU9ld=pkz%vz#JC#!A3W%9 zGKuMD7SsDX(23bw#K^7P(M5^b(=Pq>(Vs%itGI8;gfQKV$>~2X>!*6!dsNi-L%>DppVZb?xmeoz342t?U)S)U# z3V-Ond+$<}eshTlBJ2XAN<;MNA9aUth^vZ!?sDMnPb@pmd#ImYXDqxke<11ctV#31 z!PNueXXJ55%Fj|1y-$^QPIeFe36$f& z_{XS7AdAh!CZz7N;TnNA?Ror?Y=TMRg<)Vf^6wvWn%ClTcH95n^a4o-HKw_kgk z@)^GfQS<>-ZCKi+bSUQ*oYq1M_gqv$ny0sW437)fxp>HGmh4X?11=Mf=T!u?w61mP zXgK)%QFjbS1O{DAw5!Y^mOR@=PNq}@wv?}Z6FxNx2oe?%bd8c8T?%FrP@a^aTTw3# z?|*ZkNFXOHTD`NP2 zLHtQX)_uQft5yv0-!|%B z+?fb?LuNgWds8{9Nxs+--E4<)HXPv39?&r19qC&E;WDs?OYF3~;-@D|s9jPzcO8mX4_ zUWrkq>s{yEqq-f#|Iyxkyl+9XDF65+yKqh<`RiqEK0aF-No;N%JQj4TrMk@M4@f7% zdBGQyG8F?4H-Ap-U-ER#D-OE%sV;@s6JKYSnC*g=aeJv86WVueqHM+(eiXU=X|sN7 z$)|rQI(o?Lbf){jA}pJKdXpy_vyB6MCUC-JoEE~Df&SARr zFEl#`xAIQj&42Ed{JAee&0GqU#{;tRERov_pf0ez$nabDO&brTk8j!bFS(weuf_PS zpO~1<1<|P*Eoz}fum?NE^AA~w*BNyoO+a;lMol97k6vMs{xRKrr+cp7``-6Z2VksJ zXj|Vlko_k}-%U6D6fg>bJpNeyB2CYO(>vJ=<=%)xV_?1Cf*B}M&;N!pZI*9>++KOh zG~!;n!Xh_d(?&z-Ti^B-&uF#u^fosh#1Wn2&|wRr2D*IR?0o+y(zIdx*7DsEPLJu# zro0Bw<(DQ%ftTMPE>`Rmj%Od+z z6e!5}IJ5rIu)fS*K97isdK^BP1vBe<@c=_%e z-${ozdeV5K=|pBAcNaauAj|v1+UMM@@QSD2!yJAnoYj5FhZ4u_K^(d*G}HMkL*B-QZSVQi}2LC=r~H{$l;TdAZse5H>O$0%Wy zde>_!`a_{}DA1zIE^ZzE!DOdoPa|9>x;xgV7gfe0)Mg`Zf}kjclPqN{jcvs03NZ2E zcb#gBrZmgpbSDMuH8lzpJtmDMi~%-{n{H0CpPJSV-9m;&b3;LF))+M9BPa7Huo3HL z^u*^>_cy%dA_1j+Yiqgb$#1JOCxY{oX`uF;p8?`ngPkh?@mv$euzO@{Kdfm%8;rcrN&{H{&#TZ2Xl8pk^o)tH%oI*&l6>qxi*=kB0S zbtJSJeiJS__EHF5WI! zbIpz}DSI&AGwu>nF}pKRhnePV_M5Mg*G)JVRQ-k*KM{U(Pu7P4w8{?OW{VCEy>C3n zYWy2os8U6OIkVy-@7rUW{Ya=qZv^7~rae3G&j?R5-~LW@9cKP91$@+p97{RuDej%` zW6#6i@NH+U)FQV-eekkw&Z6k&-Zx7u+#-<%A~H1K>E1po-mV2&d#3maylFx#Gvkf3_L*-4ilJh3ZBt!m1a^4rAhgzM^Tw~WW43)fsrU%dP>e3QgSc8kd=) zR`b{Q=7zOMW_YiYHh%8v7%c)a?R^N?ocOL9-Z~ohA%=%lG4X6kJwx`m!R34V`Qgf*2ztR-nPql=!c|68=g$| zw5jWe(T83p*6$esz-yWO(%ab>@J1cVP3%Yztliml(V=noH5MRQ7IZ)evhF~V72G~f zFIIE~K8Xrz4gpr+AG~+-($BOj>I~2P^4;z%>{BT> zD0k*LjB;Jp?GP^a7_S*t1}AsR;F`T&)0b1iBOpe~DJMa7|NTHCHh&!a^b8r=G&0Zl zwBGC1x$a5-`bBUG>|i75Sypr;Glm1qsK${w5&s`v3wKj_)PdF6EtRTJU*%$fh&jdp zIz2>7A-XQQv1PJMW;W}z@nLA5)pbL8Aff!S(mvgWlF#a| z=>y9+)H3|l)awl?Ed8P?_|)^h|Ka z{)IR-1HjlK4kk-Zi%@pkUBY8!)w%v zc|7Rb`^xy*PwI(JrLcmA$|!3O&JG_1%*(@8oPfmQZ?oSvUMf=?$BxMPML+_b5J{92C_2I`=h1jGUy}-) ziZ*|*HGv}-;;F}@BF6^X{QFiQIbaNDr&(?(-vQ-IesZmJ2dW-Xu$dn@6lzX*DNbqp z9?Whf#}G#{#};$|1-d1!g#2V`N*r3@^2fnN0wPPCT4N3I1!Fda?9no5$8ExS?;t)R ze6v}?(18eQqI~y&8UkX$Ys|@a7zDIR+t7{w}2IHGz1cci7WHH$Z`P#sK=1 zE@h<>WtP#4H?KIpdpMi2A?6!QIm0|p3}iGO#7bdwDLrlKc4!5x3eAXreVIValSXYW zHo|#AXDU1o2sHys=P1JnC2pjOjWt=wo>eb$y z!n>0YBW?!@Nl>G`0M|Kpdm%=?k{HB$>ws&7Q^2mAu{sY4yD5ooSNXIzC*f{7WPUWT zh4W#j-1eTJV8Y(3ifCi_o|w-h#;{?3dYz@YVx=TSMM0W1w!0AxRn;|8^~wB4M1-MU z-JMD31Z=?O-Zg>HxCS05!+aAH^X+?psTk? zunVmNU=(T|BS1oE<^f>6wtx{UO0Zqk3wTEdvw^UnmJSK|bNNF?xH}{;Q#5?@hELxr39o0FGj24B_3rEI%n?NoA0Wh%ZdF63IsLH9ZmpjLWJO1>_=UX$|wMq z=Vf_ga(%!pD!8@3aARDG_i!1MX6~#GYl~ti3h#>`#Jq{|vY!5H5jvV8YpKE>0%HOQRarI&;^X{Fkd|!gBTrU^pST)5B}f2r~sV=r}z>m4U>Y z97ZLTuCGl^XL%1rdTLYPx|?}>{_`@;bNCxHf}8yBYaHq|j|Hc`euPRS=ley4hHX3< z3lJ}F3|jZJ9advWzuN1;tobNTJE^szzgRI{KwhGOvMu-gWCdcefF*s=Q=D=kvNbAd z%c}eF3XJgSsv-?F%!6XC%U*i9W`Y}J0(?-V>y}6bG^aKTM$XSGE9h{RS168zYBXRI z@R^|u;fNtQ2|8WiFN;~MhU#NCFZMIhhdee1Tq3m!bf0|4?m%HYDJ_pspe4LFLQV?Zr6&gq zT_h}LST0vDNAxcaJ8npr13equE4US_Zn`F@dP_?v4+x5TzzweC0Nr zzJ5eDvY>aoQoV!2khPP>P7~<~`Yu-t+P#W24d}j$pfROb?kM3g$2|i*M%^(}B}jj^XGwtj2Jd*u@xBtFd*y zj$of~ALo$64bZ_)P4g%P>__{ou5^xWUCBHclj@%J;w(7!lsIlk2^k%c5lUkrvcf7r zj2qVXi)b{W=EG-K?%#--BZCK|Hf_ z4#)~1TqW-;pc_at_;ed|@HX(tcJXS&iuF;-krTo6WD5Mhs2(rWG$4qAh612lSujRf zobpN?qudc9=aerjxn==k_X<2>cOO~sLNU~tAWraDejxbxJRY!$iD_3UIi%`i+}Ewb zumxiv1#LD~*fC1f$|P7XjrrI_abf%u0ytm~IB<+A{H~rys#YXtPNCAQ?UL!zHFEwKXM6NGTJpY^ln~g|6EfIai6uR0X zp#S9SHHo-RH9$<={L}9Ld>qSnKKgeDYQc-sM3Kf^gE=$eE*P|DW-nl4MMK7Wab>(Vn^mB& zk>N?wK-N`w5BpV82%o1c(UXv$thZSJrA8Z5kTvC~(WZQ5*Ge`; zspkOQ%o|;D8g(|NLmj9Y9vMbmYXa5$zwYHyc$NKIB0^91SE?muQt~&zQja1bMhW`& zg=loEm_x(*8i33ui6;J^TZ`Q&&#kE@0&3P{nT8Ul9`?xO-TA*EIV|CbB|I{h0ov@& zCYO7Mt-Xeiv7~_wY`79S#Ja=CCZII+XRiq55pXnK{1NM3;)WFn9+ zqun$;EQkPnT2RBrET{iK7-sQidHg?p+FDM5>MgMUZ|8{2h^89vm`veT)X&w#c7$D+ z_HX)uH0k6@#Qz1thjL>VC=N$D(38PPn#q3_GGaScnCxBPo6CgEsVjiG zu@!CGpW;DRtDkF%?LaJer1HoLQpHEb+4XTdf#m+Yy==+8(T>Xhdz^`mY(XVb)}tb* zHO4WSz*eP12w1TlAz@Bz^KuZ^*!}>0fp>j^oz?6 z0N0Weg!0D{=G-}d7636p4=b>wfFfq!>5|cSc1J4dqFo#qOj#}m&67rSFIdQCEQ-tj zZG|Paz6WVg9Eb55B~G!pLbyw<+3a}mbLli#3ams7Di=u2dJYgTVlkM|8E;UB>jrEH zgTs}Zqava(AP}5n34ISX=4J&B<$O#wEu${dTpQ4ObUr3lv~RF3tKtrD>_($j@=_}) z2+SZEeM1YtSS4H)!XS-A27XW!h5ZR5htq+`h0(}(kcju!#sOE`tRD7?75fZEIqbm^ zq7Z4n0;lp9d58N}v&(!q~StYau;W6a*`B zFf>EGVjs4Re2P0a-CrlKs|S`&ffy=@t)?IV3_u~TFZjY%9&v8xfz=i{rC{}uGEE_i zGSzp^`AV+PP-P43D4T$3LOZ}Zuq9X`@Qu~wOkmk%lDHiJ!f=my4wQnM(r zGI^wpAC|pTZRxjL0_2N?@;-SD#?_}Y?owz1Xp+$~5fzi_h363xl*Sg^dV}q7RBQw= zS)qPs}!C2HuK-D0aaqcvQ4V9Wz^*Fvf}MX zFitNC4kCG!*9b(ygfr@eq9O!hUnopi6pMc>FUcBn9@$Me0HS#(3lqpY(CiW(1%e&W z)QGWsT4y}@7btt@guH+l83$lkULY3F386!bbU_DY99$HJfSl<`-2q$$0D!i*3t4?q zr#0y=%mhMqhy-TVX-*D$;!e4!$EO#FyFX{3ogok}ABBRg1 z#bbF>f?l7Q$SC9Ig*iRc?+Qd-cqGFSriG={$U$I$gfE5hJE)GN2~pS~Vag-AQ-itW z1(OFgwf9aiUGp1{IuM;1|Vf&DoK*!QfL0;YeTGj(IexLPXfg_*5vm zfAqmp3siW>;jI%4Y3@o=5YaVO`Ed6&PeH==sK#2R%lB%eEoDK$krpvkCs>eh?h`^gZve&Y*Bot#nyD2T%D{@P z?9p8MAUv(Z&;h4);+3VbMw@9OfhP^1$Mz>mR4r|bnnNljHSR0xxm;MEfM}G0<3(6$ zEqwYGI%c183QN(^_Vf9oX$4^xM?EcVKB#T27New?0)ZGP{m;+;@Zf*s;Qt>r7_DqI a-P|rkN(sQ+x+6H03URb|IZZo-i~Cu|sB*ZoSixNQVF3qDInM+bt#46Nwr=)HkY z7%MaIpBv}7LVz#&Kr16Xx_Z*pRp1Asr>>bU9bHo<`;iM1@SE*F7$T64?)U0-8&&p8%69>!IN!&mJ>%?|6bK!*Glx+D4W7G8@#|+<-l+-rCZy{b=g)T z}_lXl(wh%AjtVuBf@0xi}vWZl5!ZJE-%6xI>;C=f2tfJlP=n0-qe* z@4u9Y2r6WHr{MQhX(+7A_4m#o zcEFcfn^)vhGZa*mx^`apC*+B9DvCQ+(1eyg%-UyU1!g20z!iKMaH#xh|MOJQyCy;p z(#26})%51mq_TIiY9uRnT6Si`(r3pGdqysgu>K@X)(%XQm?NJ%zuQ$NvkTn#>3O>9 zK`6Z8qHfK};`j1-JIibf3eO%wJv}9r^2kMfr|*A{S+G~GV}wj7pg2{<&e6YWTKW@h zH3YWmM>*%dDO~-F=Qf_2Skj_`TeXBxu;+sXI+RPB4nqecnYqw`f?ljAf0dxexIb3q z^IY4K*CzWMG;Gs1IEC`9(DXCYUttz8{|&as~qF2!VdI)5q1i6tt2v z)!*me>h7IC{YWz^(MFaSzt0Ie&sqTC$S)T5?QOnW@HA*VQ35GQ$mlf;py>4Lw)qRr zPu>@-J1_F&qg#65<-R|62EkW*qNROui4%g&D=Mi>tOb~Ua2fMy=(p?OWppVUD*boF zT}R0rD48H(te&Jo68`a@+>mXhyO5KgtmCQqnZUCJ8yWo?v4Q)=tnMIHeagyReM)sZ zzUY5PXQlOML!qox-imy`fi|oN64s|!ja4%kUxl})fBe%^9pRXdo}j*TgH#-)iqV3e z+7eS1M)B^T5bFyoZjs0DfD0|uANxKk;12R{_Dmq zAaS>V86C{^X!3xSP`?+bLxE3$q#j9oKVajFdy1F#iO~)}*iqI2C4&Q7bsZ=q6~OqG zn8YJj+=sD*lM$P;YWL3!Izx;ooLdZZ8ClO8z$*7Rn}-YrJv^il|w zxVN$4lYyR;fBTn5D{?7XEB2)+rbnL5C-irikuTe{X&UIv zw>#U!_NO`0C^|&BQM#I8i_Yv$`a${)BU$GmuxNw7$3?)Jxar}iE1xbJRq;3aIq3Ia zmPWFLPkeLDh5k{@QCvc|K3xV&+u>+uP2PkZr_4P0WFa_!LiRVBWCu3cv& zt6mr-fh@w$U5>%a=dK=9Kc)tH^8Q=v1y1N^fdm3pXCy~q226({iQl~C3UN-vM~{hL zOxK*XNN5y(FnLm4KRyU1U};K1C?S;9REH8;X<-G9%}%JWM_bHX8X20Qag@eYU(3U9AX~vNUPw|T?D622s^#G76wARVzW06|G;h{%}uFu zi%iNhLDvX-Hip)~L-i?_HSdmI10HD?i=!7yhxVQOp^Ed~-mNq7hs%rJV)%3#*v?nm zzI1VUGEmy9s8Q4iO11j*tkIf~5m;yfK|jTFbmOtmB|JBTCgsyK`uDsig`jmK_HQy< zu~AQf<{IQ(5|+jACj-tqcUSfSFMrj=%2n$qE2z|q`FvhkFuyG!YVI>?^`0IU=jOPf+s{=@TeEMz4w6EBJ^unP?Fo2_5~~$- zhCc=g7ES1K%oDvEy_YPvHvL{!?Y0d1_w>H{ z9fYnFMiytU+KIUHi`QYGA$=LqKKQIsK54bd`G}9vpMp&&4M(&PkPhXtFlr#*fSMN%gZ z|M&v5an!m1FFTC1X9Gs)jt<1KE zLx&bIxfPj^!AT(tsT-Pfh`A@0-=A7?IB5zQpMaDZTbyK&kClE zGPX|DchBbkOKk?|%7)K1M>;|+n!mLe&1?_J$>MpU@~#;dN}cOov~7jVirJdSSx_?N ze#)RUt^7qT?N_LcGkkUwbW6hS-O0~m75KN69Cgc_(B+V)1)H}cmOof&tAEQ}{dg9* z1QDNb+Z7%&-GxDpH%du4Hz}NZV&*Y)T3aras0BDH4mqH9R$Ua;MZLD(kNWZqO{8D-Q{ypY(8xOa3!vsrhAXHMzzxNqcBI5+0DyP$no*}jY5-gE27u?dbppoYxoYJVX z0Pd506{xyYOqaads+^$c=EK@GlUQ1TyQpE4tioCl*ccJwD~3wzG$ajbd3SlzDPR2C zHp?PlwJC2|uHCh)wixleh!*)j|K7eZC>fVX%4JFC-_g}wIfJFugf1j6MGGOEO zVn`_FLn!=O52v5=(;RcDC?yF`ki8Jk9 zkZHe`@1OmyEtecS28!uYaujZ9%AtgPROdG_cb1uW_EJeT(e|n__|s$g@_80yy1_?H zPdoWkQrb3kxl1lXx$AL6X21!;U+?a)xYu@8*E)q|oIuf`P`HH>j=gnst)~(W7fQdr z#j=EtUw)jqvn=@QaGd?|U;V;BS*5P#t8>LsNkVt4{O9KL0-WA9@EdgbUZ(#egp&4# zpk_5R*7vu47d~j<9kgZWEKeoU>B{=Kg#yso0aV)hL0?~Pzjsx1r|ME^ zsj$y|P5V0ck5!s<0(03KayZw$N^#$pszYi&cR(^$V+mz)YdriRpIecICW1Ox9(>lLfx zCi(>b_;FNWuGmDPW3{KYpxOSo^Dz>ZI(2PQ%Q3{LTo(v(5PW^#{{0Nfy-TL7`h(kX zPXolLsMvj@MDE)1ip@ge)fvHk-ABgzE^KhY-F?fgUk`rgJ=X&*+nn@P?*|m9Pox0` zd`@G-WfB1O#Z?kj>rPt5lDa)$&#imgN@Lkry`K}zO>2&wW&5uYenTCXHJ2?Hv%&V7 zRZ-0*P@^~r28E*?I2M^j?8{!?AZ?Do8w ztSbD^TjO!gW}hd3Ba*iMyoDZoik@k?x(PenZ>(J2ym{?pyUnsGss{34He{G)SUcP7 za5WX>q;;+SY;cUKTUY3QaT=}gRtm6F^lM7(a)<_pL#tzZ_b<&|0meFU(D~#0gKzu% z7Nq`2d7b5pXlx{V4zBUd1jBRj&G3$n4CO;|y522)GTj3S!fY>J%I6)-lEbiF!{6U5 z2cI~V{lEgd`{SwI|G7x7?r7U&DC4I(9|=V4#zhNsZN_yOZgy5wOLaeTiex76E*JIv zTLx<=cb0jigH1$d4ZXDYV6r-Pr6Y%Ud(6a&a`9j2!%&FtnfvBO4lai{9!<}n=kyJB zJEvc@VxZ{N0*(2@EMN2G^gi=+f%p&1!ru5xv3L%Z1DfRsiz8yY@pYe;m0}xoL@+pN z|Fu)Ae_gXJ5F8cy8=ja-t#GFZDv@A8HCPLZ-|YPe^9O@rJM)w#JEmDRIo))tx^LD( z1z(M>8<$X<;Felnw?+=X@+~_U{nD(6dbCw~XQJ~SHE&jO|LRY9cy3oTr+Al9o+v#2 z)f3hC$&o1?8;|8Y_J2+jajp=tl}Xja9BD6OaIjybEZhHLRtrKi7kRMmyVjnMd*#!r zV|&`@RqHil1%30H=kM)X8p?IaFYS`ry+iYEJ`8x)ov};Hkq>_-U3an~`9*k0)1Eu2T&q6{LcEqNQrJK6 zE8!LI`T%uF=Qa8^y?MRF;iX&T!#K<%ERV-{zVOLb=eDxlumI7p5}9r~X*s4#xfqxO zT`UZj36;C6PySn_LHAy|iNsUBo2m|`Ref8x?O6WUcjF$R`PzjQ)M9x~9BXNa&{Bs=z;K%qolJ0V=iM!+zJUg=n2YTvBJG z+z#}VcLkF0($h)W-@d-+yMegXl8Z*^q~63cPj(-_v+E7SXc79e1?UJQ&E4@T=dT9r zSN=1vT)U%8R(3DS4cgi29rjdk7VH)N_zHJ%P$?dK9lk+L>$&{ud|OYv06EC zdrEu7%w=8a<7fOhm%EA#gS!By7$4WY8X7Y1N>%Aun_O5{oSViO%-u=APoKQ8tMo>r z;)8Z;-|p%5q7|A*ido38pJ^sw%@r|kiB&P$gwsL%I1700`HJN$HhxGYR>``2vB|$C zQBYCdY{!|Yw(9peOinqj>1o7U&AyeK_;&(akG$h`fD*y-)At^IRp$NiR&)^0@0nN- z1B`rK?oVM~I^gSh+Du62;}$Nw`{6>G5KG+dV<$VVW!u7v@^=DktLngk5q^;ABGz;s9{5vM7{J(f%9t;8bzZH& z(a*ksNqGn_$A0Iy&ZC5#IonTmQ- z-@>bWC@Sn_rSAqLHLf8(_|I`wt{GFj^1FiW;QNWqdH?dY|K=&gs71>*yG&wVOf!y{ z(|oi)(JgByow+m8zbW4mQw_J(Udp(6mmRL%)TXultE|&MF;x6h)APh0@J6@Y-`6~X zB~IC{W-tKDVt%Q-q@F`pGOSz1uUU4|0cAlgY*ee{(J#rhEs_O;OAjXK$q{w9c-P_R zsi0@_KP>xwHc>P1_bV1`Pk-`)Z(sN|_yT_lBW*%oPwSXzaYE46WZ%W~^6NM4a`Jyx zZT`HFMhP!AHL=+X@C5yx;(yP&e{bzKy>W`9mP5Bko{@0kW;vIFp9q+(L*y&WL7nI- ziCELEu8*dgLh7gN9v^$Rk-SrqdukN!`0&zp;cQJ zRK>XVpD?z60cBxUah9Ox7+*Si{gEGxFHXW%&^n^It@%F02LCb$+YIOr8{YE2pOjURAv&aA66xRh0VC z`TJc-WPWvQ1OtfNf^Bx7X8y?kWxcI3@9`j}>}es#@t4O&a~gjccA<_pZrL<`jTJjC zV5HEPewmytE~JpSdS%rVM(*~#<_qZl{eAZ+ZNA6w68@9MskRHKO-nZY1KyT8fWs8a zv{&icg;UJis;~;EfUch#6*zfq2#zd7o6Owz#i^MWzj>Z#HO1K?j!Z_kWL4%)8$|f& zlD4OjTF3No*Q3pM+L{NH^Hn(|!Eu?l7PAFi48kPR9~m9xrXHL;Ak3=O&GFi5ek>CI zAB?vzw$0#Ccu^S53xpgR)Gh4}q~a<{Q~a2u^Bi}GL$WbCRw3haDs3n|k&E*5tXBxw zV8TOAumPyiso`YtjJ%_Qi~iU%ocKEYaV%dfy>ZxioiYEY;F=<5E20Lu=V2MH!Q4|P zC-`ULfO>jCGvohU#s>CL`CBjDV*A-cy+qtvl3#+bdrr z;)K17)ee1vD;JxrMBQ0pO#o6u4B)d*=6jSD)1adaLuzMV|IHU}Wwo5x-I7!WBRe>F zg1_za-_?FEZh0Es_bd34Z`h*k#$TANa~MzD zthn$JynSM2$Izl9<%RQL8@-=#=Oc6+Znsw&2)Ap1{J6p?o~~H8c0n51#e%dRyR6zk zR%HAtjx-sI&8xi5cag)aA-`YFvV8HaBEP-BO9An8)mxxAd~Il-%vxxU;(g2`_;vUH z`HJVKhc{;Nv3KfF-`ZHPw&AMi8fg?OqHNR{0OvkJ6OT%;EbbuPW$~gJ5l-U6C$fjH zmO9#0V^zZkITe=-idpQ&9@LBTqvMv2^bZT|(>G6l_|}fml6xrz5<-${ zXM^;H+MV?K?FP^QW!a;B8vRCl*i{HPXXd~5O^?>CUC$%Rk7GH!<`WeW78I_50`n-- zlu2g#9B9HhU42Sj0BH>NL&VIQLd5CUwAu;S4Y>w*bUcmt`@$4Y|5w*csH9RFr3bhE zgborlV=v43V?z5~`)+nehh}y&rzJ;0`_rJfrVwzr@n3vDvAU)2v1pYh3zC1Aw@A7J zdjxh%Fsv;%uX*SiA9H*Bp3HkjJ*=%K*RyH}-2B{U5j&EB$rI#q{^2a9NUJU|UX;3HouI8wn<-?I7HICDd2C^$Js@dZ8{9(H>` zQk4wSlm2}5z+nOUHl)BKj=5v;?cay5k6X*6v+qqseOl09LG2X{Tc*`%yu}w z_{<-9xhGUgyzXV6L)s(RhvycwVz-`m6=9-w_sZu_JKL`Ec^1Y3B(i6a<+p7*E9g?S z@LiN8!>sM6(y#KX=>|i#?5dJ0?h{_{4)X$maP_~1d8s%CI2lvNp;@I@FCV=l(BoHF z=Tdg^rdkE`=lrkLu;e*`{Jl4o4+Pqle9O;l8fvQ5JvJ#?m}E zr7wt?e>bID)7=tspLpU97SF~ZK?h_?c_=U8E5LO>PswQ(Uv(O_;gch|u{D}r?-Gl`_jI`umYWD3D4*OEiH6w9js6B z-((lpIGjG#wB%rKUKvpdIhXnJ0Q38^CZ5A%NE|i2eLuY}vuJ`QL0+JC*Zg z_oD{E<_Vk>Z`Eb1po|Vsz`b$-)n#s%qgb7d_*$*I4>laP|0+tr12z7jD)989Y9`#k zv!y}|HaqD2uAN+a5P`vZ$;Fa=Q)+3Q)7>@$E!?%fvg7@iml;oG)i|mBL=QmFm7afKQ%1$O&jBoU8 zY3^#3HVV6(Ffb`V8RzNIHTRB+c0r`o`dRQjbmO&GUa9H+P_~ zkzZV=;1+epi6`ilhFd0hCq3muI@@b(%hHF%{dd+T#apkqMi9Bn6@}vm-wKmE4(K_j zjwN?H-+CK!Yz%yPz7kC*hjhDIoIz$_UC?0RG@hwWxz zEn;Q|xK%j;hjs3^5hs|R&ntyjTD5kQA4Gle`g$X7DW8k=;G}OUt3&QqS7DyXOgGgp zU4Yj}s~~BsW8Av;YFf!-<~T&qlD_fC@Rv$~WGjm)5VGXyvg`9@tWwCC1cD(zfE(8I z4;by;zP(Vzpo*|2tBC%gcRxNcYBdQX3SGayvB*W_+4}-7NzA&%u9jOGn*)`4;z-iA z6kn+<9UNv1YjB&MpY(9tHupCmOSpICK(z$j(rcE^odM!N{MVDqh64o&V4P#}A?EAQ zfxjTW9yxS?5O?5U)T(4r6|~ooo-81EuruD2u;n%(bHTs_W{OtGp7BO6<%Zd)Glgp} zUV3?p*HGY#X#$@1Jf$#Ga^)FU--__vx}~`k&^3WOo!2N>4xo3H`rz0=`Ug}Wq@ft& zIWD|D$-Rh5;qV7?5+X>#y`dIxs)B%wxXKowwW0W^?}nT=J+!ac`dG?MVKpr8=?WVtmU{}&ZU9Q?Undp~8#$tO0c83c40 zz!qQH-86;v0WR%07K#I@M!)@c_fHG6YTEsPrl4UBMFjgx)*6c5ecBjq#cmIT<90~| z0CXe8Aoh}Z_H{Y!CNqd%dAF+K=c39@M|fJWK{ArjJ;k)3A`^<65QOu~offx`ysU2% zZ*Dk72(y#cMM&mDXAL2eJ}tVkjntyXa8CEG?COuox72SxK?K>A;s6ftV0Aen9B%`1 z3Vdm60*~i=?~t9ns}q9~bo)YufzExW&GX(0k}QTUH-~m(2Pt zrYur)1@L_4#FB$?Ddf=K-`vBN#j$vCyguc#)3gR(Y?^og$7(*Y+`vu{R%2Mk+}Sjc zRn~tc?I7@F1zvcqA#og2$9(MVxIp{1B;t3&m{7;LN4RDFdJrJTFSM$;5sEoxfBq-p zF>a|dMn~{SCt#OFMD7CR1H6DBF&Ua)BkeJer$;#>$QhC-GFOpwCtY>Tjd_I`)9uR?0TV`Q}nRsEZ+!kvWUVeJU$iMU`w~2sD zR-|X8@oju4jhe(PG9^Hu8b4jdjE3Gp#cf#jD|Pla$ZgIaT*%-L0n# zetrk1$vnQXXP6VTGn(`0IeyWP{litCEQ%bmDi#sMh*so=-cPCYYFctA52vI@L1Dca zfq-o5ghv|*k^d#BC*}Fq2O37^+-;gaH;x2D&*qDwksaJ;pAQ_sHC3Q7JNuh5-)V|5 z`1C3TA(RLWB<1e-7_N>ODdWD6=^rSVUb~^P$MQ&%oiSa}%re{ly+*y@gaZfb5cmdC zpTY_4547GW@8hd&=6ThLg~3lhJBp8u43{pcGhj==0)M?v@o)35dl%cM4Dh8M^|j?d zt)V3q{X66YD#OqL=rK>ZV`iys7clrfru?vCOYGzIykJlxkp`&zo@g@Pr*LF>g)@^`LiGf49Rd(6#ONgce z1N{f;?FaR+a7P$2bC3@cl@Sx1+cLr4tTLfPR^A-L6I(T;*6G|dTdSyIcws=HwD9zW zffneDi))LWFhe#pTiy-gCvg)<3}6V_pe=)^%E(o}9U>=3J@Ol=gw{n%ZU5deF)yUWHwx@~& zIJ*wn4P1fg+LWD_ee9vxu&*CO);c_1RG6&xkB%8EfFblp@N)#D{EYO#!=l&sQZ>GJ z2SA>5x;L4L|4Mm1OcPbRBDqg`zs8>uUE7y-hyTe46=qA!tIwa!!b3t$=G%olq@_fr$P+w zt)`0{oXQ&=YRyJ9!SpDH{)d*>{}Yb&WAZGEVcOT=VE?(ggZLF`+2**S&4K(}%L*KQ zRvsi)pCaew`7^IC{|T~yjI~wf6?S%%Y3-^g7!LZ14ysp%cnyGs?wYvhpE0G_eL?SP zu9i&VE2tY{xX(#MYFti(6NA{YddVe{-VYaN37^QoEX=EX`8Lo37>Tfv?U=zRo8ViZ^~ir>uM zw?0qwNV%u!C1M?-OH7b1N&EW87V}5s$%Kp+$Vl8r4eLwDvw0~Mihv0(O;#Ho_-6Oi!AqG1QcPwuKdphu^8Pss5;iID*Nl{hu-o8tU({rK{Jp=C zP|q@~FGmuhw;3dB`G>wF4Av+RzR|_y5|#c<=}FE_9TNrsMEsAwI;ofWWxz_SN{oiL zH5P%JRjeB~UM$MCduM_vQU6)6Euj@+@u8I>xW&3wYiLtqlQA{SSsxxK#;MpZwlcL% z=aBvBY-}l%Q+cl?!o6;0;kn5b+!`OSA^ghxs^&#VuV6n)N`Ui5H{TXNpiR z#ao-i2SaF&SCvd)69|Oh;Y1i|&j=kn$<;1(%)A;BFJGbipTEw~^WdNKBcSg~Q$PA& zP14fvuS2L&J-#V6aePl9?`K=K3NC&hZMO2aP&KL*n=Hf2&u=EZ%$gjJUP|m%m9FH!?PgKX^<+l$uqls8z!eP&mXD*Qe2p7VBA^~C^LxzHOx(FL- zzJOLtFdcyz-NHl)sz42env(hPVH2mdi|0tSe;!z!Khs(|g3h6LGK!;Rs)cXBp0!-; znfu0lL1N9?Im${J6%je`i8Fx7UX7l$jlFaB?5+JnPjfylkD5xfD@yc2NgmsBc_Y&@ zqm=iEB_H=A<6#`;@fqm?I9Svj1TTLyEedqKaO;8*71F*#;PMDZPe5#<@C2*iQt%Y7 zJoP;@Yih<~S%g!mKc`g2g%%j+AY)+6N5G;&0U?P20Lw&3x6qC8dE+yUZ}O!U#pb6v zU;*`Rg_MhWy_RD)$M+Zst!`HjsSehyv5zk;-*vs@8qKm_z@v~1)jguZzAf9bs2cTN z#blKAbIc|1DjiN)&BOq8JGm{BUUyh+LNTEZMYq98Dnj(ik{CNSgkR*bc_ZNQz7LgY z=wKcn7!~^;AHfi%->S@Y6R|U6Jl1nUX=~J-WS&L^oo?1@W|ieXm7bScoJ*9C*=2|u zIM{yDJnP!6{@)+JV$SbsL-~i%?9mdqHK8B2JyM^z)}0p)7Yfg0yi`5D(%;rDR@~Pq zyxe#K*K@X^S7jGA5u)YJU0Isfa0BW3h5Jjp=a-J3AD_ok0r8i(8-HUapo?*!G$$bn z5pth@WP5a(k!fAK*ztx|$g)*`PK_z0BV?pD2;0^U|(KX#L;XSl3t=uLioGJNcA z+0fg+p-B#UruNic(> zkgxHcpk@{BFYQ~|MkSy3JI9@!oa?2LH0B2xs9AswK?)(^#K-Ub=2a+XS7B7uGQ98u zy!2wrtD%c583LgZYR@sj&r0829lR_;`E>xTpQ}5gSC6~u#=rc1gkD?YMlZ^ZR<>`= zX8kBf*<0nYwYudey&*KTLN;{B`e*tbXTiofzNIe>q`{!NY$e8zjQpR4*>KB#m03hT z+^G{9Dh`rbX{aDFxu>5fJ^_v8J}vCIxTay^0<4=22sJumz8F#k@@xUpE^uI{Pi@e) ztPd0rNpt!J=iKtRJiQ%LN>9CCwE1j)(h7T1;+6`#)Uq*oo_l`wsC;24u&kA|Jc=4< zKRD1;G@VR8V1k-XO$w;IVARV%g}U;fj(%AhTseIVS?Q+%Ja$eC6Qdb|MicfKD2T&` zWAW2mfMe@XI{jfT3UCvAfkGXS7h>ZK36$_Rn3mh)mY?zkh|;v8_y{`MnW2JtC%=yt z=4UdHc7rMpCK;{9U=y}Rf1eV06h<}pG#|+OCH>vDFelf;JhRG#0flXgffYX?V6l8Gu2q*dfz!r+w}RDZiQ=YPl(8g;;jL++ zLu!-4G~=miA}ct#V88$*Eo!#&MQsl9!N$?4=dc0rfZ3Jx2Akkw>26y}yW|V}^lZ`~ zn2nRb`?6icLEq*1;dd6poZ$U#;+w#g&6lw`H{qHzc_AO^mHppFXY{Z-y$LkG6Z24P z@Y(0Th_Y_O3^!bc!T%x5)jj;z2EQu0jTS`G_+EL(fgcKZBdiC|(B%(_R4IT!yLGfrb}_7)z*ZKe}`AoekjhNNV6IP8(+at!k?wRReD9O;}n|xO`dG7 z=fun|vIX-KD04>)p&lEgNot0~U$CMK7Ic35 zA}VS}=2S@9IB$#)8jX`juv}AR_g8RNP8iwgz(!@aRb~OAz8nHEK?boYd@#-_->?jQ za9myF=Y!{~7K1nkt_O>UJ6mUP2HhrqDbIo81;Z%&0x>!CR!|g=(vyh&+%-*eYI6*t z(A({^Xl|)EY{Ha$dAw?AR-BemlDQtCzX$nI36zQYmw{M?rLHF1l^gOO-0GeP zB$3Y(mQ>GVeYnsSJ(M3f%W^FbVTk6sKyi+q8DAk-%k0Q326Ey$_Z zXr&0K;Oz&Zh^C_mge&9fOAeDxu1IE-u|1cwy)Gg?n4`Nb4hp-BSqe)tpD~bk6(CuV zFY+|=w7lKXj_fn|R^Yk0$6`-lYkr9HYW6eJwI=bjyl+#zs+-bJBs_*xm|C2U{*F+d zP%r}2aARIigf(}VMaTh6Ye-Viaq(yl!O*NHquD|})q0S>w#UOq&bq~v`o?rTSw=wF zX~FWO4m7YxWB8Wj9|qLLdHExWY_#vtUp0W#0sB98IiO zW#?~JY5vk~sGzI=r9BGjcGj(?-VKjC0+GT8zzy(KtC8(c@3VHjJ9dwJ4Joq;n=Fvg3~TAl)kT; zSeS(uMzwQD`BQ|Kx;PrBc>iu2ev3k;R79ci)OOn;VgU}0W6mo#1X{%Q1dkf*AVT81 zw>kdx{hL465cUMh4WO~h^Sg)Dzu{G|W^Pb2AMt79=lu})x?@#44x>O(=?Q01$qpk~ zl1)img)TCpEECPVe!PXC&g(}O%vL{mZiY?bV>fz(FIW5%0nD5c@knJDP-0~=b7{Wa zf~P-qDteLun8!nhlXw1|_;AP;c$5*Xpuy{)MHEM#LD*v` zcY1%q{M)2eZ2s%QULSX6!FRf10zdEk(xprS!b|oJcAPiRqen`kB)n4)y$S}YQyqh> zA%-UQ^Mhe8fEp)GUC^@9yFR~C+70wR{m01fb1py|FWo7a8A4NnXDb1dC}=>O6nvZg zGX@HT>5F9?Aj@Sm+l=WHT{P+HwgYT5;?rov4~_w)#J72+%JAyIi*}UkvomKfm3hK6 zIqBih=Ru1c{6(dU#E=7q1r%A`U-RyDHz2$M^94^|f?>L-JU$S{hd?4J{fri`Xkt>yPrc{aksi_K!9UIY1Q$3kP5sYXD=zKM8zR4b9nqu_4l z&t3cuHfYsyRorxvvt@FLZa;Pq<&N3A(}f1y@55Ia?dD?b+N-XaY8BqK%5~g9e1yke z0W1d3F2oDpXY;;SR&*UUd5^zy+jXx5(rS$x2dQD315k zg!}Qh;{6xT`}+<%8aY1wv3MIu5pbz_+8BHo56q)1h{a)Vn7xXF4PQ(ldI+)|ixDURo0GBSBsJl`362CJ=%< zQi4US$Ye4{A*5*Era;`ovAh)GK>2sT#Fcw2T#ElpW>pm6N3poW8<*hR5R`HL1Lk{# zr`2pgVlyklkB7UTUi{BDHZnrMm{|del0rf7jBfl-J_0j1K;`91+Gz`wD%nF12tZ@; z((4X~u3QL!Rn&V542;nn_*4o&@`CAA*~E9NV$b|0c79Ip}G z;yegg0yEE}+cR8ZD}}&WC2~*Mj?hSygEBm zvr6!nzoXCZ1xmZZY+vadh@sL=0V8QGPLEEB&fJyTsCEDlGL7wBnYZ`t|?{Jr(e0CU|hosf@6V zc1p#z`^5gvYB8wvi2H4d7#0Jj*MuMNR%ILt5FDVVu3Kv=1RLKM?vd$vk0+C^ly!U{rkSz7>4<4v3AL z;zoGHd(Fe&`!8xMWjqoYm03-@12JM}Rg?7l7~uv&+QI(LJ3OB{6zU5*jaDY%Ei%k+ zH#&*0S4|RG?QYS-4#Z2kaP7JA1l~BHvF|3U8=qDxoZEn*57uF{e z&f{n`R^DouTyi=CIL-0nowCNy~4qxY!m*?%ukAXRXoxy z-Dqb&MBoXY$yC)<>t$)l@%3GYlq>({vg;E-@a)D)e0gJh=_1G|TgYd??m;noKopru z61+IdzH{y_L1|CSlAzYK!$O}ms5a2iH2a$rRv(KeHs%f%<^pE6+h4<6y#M;9*)VSs z78){Pz6Q>EIg@WVGJl6bwfR{0mj={O0wwK5ssoBm`+%S9Ohw^O!I{4XKkQ3+wd%}@ z@6C8|2WA*{@DiA(gZOP1)U`9cbRS!;gQI>i)}|;7OPR?V90;26gp(tLNhwDJr5>J zAkSFpkD;MYKvPv%Pbh34=B1t1hD)qs5h@mFf8la~an~=oNIQ1*F7x~6Dt$F}zsEUO z1L<>dv@g3xVAuJUWAB}G%f0$oUL|p0+*-BOd68E^(-nlUCf(F!Fd5@{#k5DA+3lFM z=*18-j-E;1x2T}yG`g!Z4uT1AgC=iQNrFu$vN-t?W_&5lNw(LYsAHUivPzV~C|5R>GG}wFbc?{kG zG`HLa?5MJ;3s*<&Zq6QY=PLbQJLmq-^#A^G=Rzunl<{%iYVVA6MTiq;+3D zvqICJRtsN5{vJ9}`jEk*Vk$?}vRSV_JMtbG3*1KBPEFWzP5HXho7g9mXQDnEbc8C% z!@CW)xRIfxWi2_N7q*)qvyc-i_(4yddr#&(wSykcnhd|p+8_wV=t~RLeM>uR@qTI{nKui0W zSJJ}}aYS?1Gc7sQV%Oyi2R{2@{hU^g658boiMItV#%URVA&L7?i#*)asWyrSq=P&P z=S!oK7IBggQYAv+c|`Y9MOC=#RMgYTe@91Dy=A#2jL!VVjQf|&B%2RrM7TOoI>hWa z8S}q7cGsQ(vdJMeLZid?ab`&7bqP!LY=h4JbuAt#(}0l8s>%2}#aW8~_RzcEu{oLL zRgzTP(uZSD7d3*g_5*=z;zY-AshT5mK_Rhw^b zvwI2og|8Z0(D7xR_1N61hCHtH+$fS^sl-v?fpp@VvOGbyuRThbi(s7Fm625>2PYIy zXiz~b{j209DORU#wi^nWib4=1X})lGxHm4>fIlYdg^5z9G2nr=J35ACU;g!{@86%uwx~0gFQbtb zJdnlD;PXf3*1FiJ;Y1u&yb|#ndN21tRnS|~6R_yufpC8*%`}4;%gf$w7K4+%@m!y| z8!8`G<0mxihTT6|?(wLfE|exZFn^!En!nNbHLv?)09Uamyux40o2jjbp|0QGh|Z|U zH0dEH$>~3qxnj@x3{(I52rUoZ{ICYwirJYcW88c(xKm^9bt84nkP*0lAD;esIYqIY zv?`@tfPQFyMQ**z`va7apR>JA+1{`a{y5|7vDlGI^6@v_5sqTn>wUB+GHNt8Asy$udAQWYnj+b%6}c&!2D z{e|6y)2TUm=wktQKrhBGkSBOa{Kw#& zXiYB+Q0{s`rR+6Jex1mDjwVwC$5=f(>|3w ztGfc@ylBO`mCrwTs)Om5p%P^ol_5@(2QmY+_%z~R{mu9F2)&!+OU(&zoKN9VeAKcO zENA`v#c@|v$^A9QMixY3EFcwr{a{;b;Dlp*t5fu4n47cHCFT7?WV*N$@-~9E;48}* z>RXT$2^rbuJlYA0TVH9Wz0xwr9`<8kDl4~0*K@+o4fr|QP+9|tY}^!xGtKEisZB0e z^EF*GDA)-C3Qw-qo+|=EAA)2LP68MIE99=Rw1(A1{G@_6R$X>I(V^{V3EPIRxzs38 z5PxIfSCjKf%ebo3o6OGq^5yv#Yj0dQa)3g)$??U5nnBXfv0+nDzm!`~D8!C%Da`9y zJCtyr0(vq1z^o$nQ<`PFLB(x^)f)g{YdjFjTm)%ThnN#Lr+&rrmNxE|p||r}$daxu zvEi_1fcp14$`@gMMor-#&bzs3X=8}BR4GhAWQ`+93?zf%dGuzd2*sVLn9I?h(?j#R zzYVTt5HCH;vo+s}bBH{{Svc!zHdys*v>6m?@H>ao3lzdH`K+)LM^>ZL4z=$t28tH9 z8zyG}2*V|nQX{Za_4o}H5_rNl60AJ|z*FEj0RVAWK=RpP@SbH^#F7obL&tOBltnzZ zXC`etdQql!gm0GC1J?iK^Yd>VZrk`hrKNNh()^=VFr~|J-QRv@wuq+UsHm^CyF&l+ z5wQag+^*y_N4nTcyB@3r3eRhaKW}T$=wOKg(th#w#A^G;+oD^|B76AM-nfF>{KSWL!@QKn znpiMNX*aGPn?u2`_5uM;G65ZQBCFozTk{=g;890gX_AN@?xN$Qq1cuIupug(86rgc zUcPSm#kNUAicec;#6Z$#2xq#982zm5HbOd#OMxFmXx;cbc5Fx!En}1z-=!k?|~+s3{F|7@)v(kg7eQ#M7y$xeSnuJtOPW z()`k-=flthxQAviJ-C0)JgtBZp5}ZLiB;oSg8dL-Y$A7{Kk=mRQV6MWKlFnuNpfqnu)0ea z2Zf#4SBPbZe|)%GVQmHr%|VVizkMebSBw*OXMSk?9;xJy=k_*9(Fv!Gx-~kHjLTSM zI@d4Da95XG2kghW?r6XFNh^2J8uYAt!oXe)&6yxhbT! zH|nb6OI!~H(*$4OQ^`mVVJ5e?A)S%gkSnQ?5m9Tko0#!;Y%%KaD!%p6P{6gq`^C)( zA;YHs>Y%?yvqU%Lt$gat?vj56It)7l;!w_JglaLCV+7Ld&{#?iOU`h6WXHCt`M{}e z>3DJvPn7`UnV1bS5$fPr1>ErcB0;A*yKzbzX58of^cC49HK09h&k`RNns+_7m*RwJ z>(024ab9d0ZSSTox1w2IR%Ovf^kBT06Q_v&NT6n6_W=A{dMlXZ5}@Xh;KTt0PS!?I zV|Gs-1MV)lWD0E`^>zn*mltzIV^OK#;AooR^80ke!`QM^1Ps(7BxV_+A^)b&VgHjBW}N*sIW_idnI(*xKF)cJ%($v$|DV>*$Fgu<{ee--PgpD4 zfml%2tREaD@b5IT75btonVx!7|F>aEA#cOhBb5tmyqyQqWsw1Kpj&RwVfo`$I9?MO znF%<9zs*a;_E*cJHbE$^f@nKotV#=wh3sUDk!fOKb)QlE(}%t)IjtLaN=e7STyi=6 zEQ@Q_Mg7C%@;_d0`Kzv_WMSsYQBVu*G44E(T#U?E_b8vU17p1?z)Y;IKuh_BK!bV? zWznBC15M+#KAt-v|GZqrfXlCLv3hZ#^NTvy!@e@4ql_`jl3ALaP~Bf`rQ77`^OMrq ztGNhy%uF`Op589{a1q7*M$2!i|ZHKZySNJwpBuASCfk zWQ?pqpltZwqi0`7Xh-D28)-Qas5!54I(6F?a`Q&ow-AC_feL(Xq55=`uGf!R4dq+wv);-yi=j#Sfz1DZDI8i#@TG4NNy5v~* zZXjRUj9f$9OJLG3L074CwgT3pJtfJB>om~+4+1`|m{fUyfMWBaHKXBd!R-)Ce>{Rl zY1fqFyUOg$=Lbh4s>3dOyc#b^{efO|lxQj%6&fWL)9NR@?8A|tZysF16(#QSf>HU%w3O$Lot6K)r*E4ps*h z2<^{sK)cGeE8dj@^~@s|i>k-ff^VJS+OWwDj`K=P>!u5e2_0R^vIe))40m%_lP@VO zOupsd6tc6iRpv^}95bOvM|_a;cy#OF8l`d4jhcgbWshqvegrUdyV#%5y1-jD-mggl zUry4V>F&xvek|OLvFNk()EUAQcwKCso~m90#l_0oE!IUN8-}WZUdsqHLota4C#d_U zMedF4KbCZuffmr!`Fx{J-yg94Cumyy23xBDfg*qB?I{t6lb)UdK*-K!Y(Zg35erGhE^ zM=uelF<029-?hWqi$C<9bCax1I!1T#kg%6oHTtDsV5GkmPCvX%d-lU%cV+;bw@C2#nLnU)7 z(x3{|bS_}lqLb}MWcu)uZXGq>e>1)~)?0?jz<#>z<-q1mY*5X#fSo53R1Gl0Jx7jY zGR3+3>sl(MY$$8mI9vXm?fic??y#zEOQB?OY+uZ~EQ8reC;>jL6f=PNyRqY~mKWsCr{&|CcIrfo3ugeM$fHt0X2PYMc*b{0 zkXsio-PL{d{G13@SN2z&mHg_hw7kdLzR8NIHw!U?@i!9lj_U){6|(yA0}l88_Ll9# z!$M=pHmS&SV#MjSajtMKoGFIjcy4s_p`jJ^{|aWxq34O?MTH;0uiJYbojgKNWt;W1XI)hpVv73o zDl)~WyqNaz3SNvTgB{`cx=}9TohQBa@FV#;R(g~+e5+G**$%{Z@&Y-!LrgI?T-i#h1P!EFUKoa-!$ z;uD#2y3PL^E(d9+yPeQ0vIcM K%gU2p@&5&S=Du_Q literal 0 HcmV?d00001 diff --git a/renders/points.PNG b/renders/points.PNG new file mode 100644 index 0000000000000000000000000000000000000000..4510419d49c0b1cc733c14ea6f0b6d2694502149 GIT binary patch literal 9734 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 OPjroSY9Iak`u_kwWVdSo literal 0 HcmV?d00001 diff --git a/src/rasterize.cu b/src/rasterize.cu index abb7fb6..ec65824 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -165,17 +165,19 @@ void render(int w, int h, Fragment *fragmentBuffer, glm::vec3 *framebuffer) { // TODO: add your fragment shader code here Fragment frag = fragmentBuffer[index]; - glm::vec3 lightPos = glm::vec3(0.0f, 5.0f, 0.0f); + glm::vec3 lightPos = glm::vec3(60,10,10); glm::vec3 ambientCol = frag.color; +#if TRIANGLE if (frag.color != glm::vec3(0.0, 0.0, 0.0)) { - //ambientCol = getColor(frag.dev_diffuseTex, frag.texcoord0.x * frag.texWidth, frag.texHeight * frag.texHeight, frag.texWidth); + ambientCol = getColor(frag.dev_diffuseTex, frag.texcoord0.x * frag.texWidth, frag.texcoord0.y * frag.texHeight, frag.texWidth); } +#endif glm::vec3 diffuseCol = glm::vec3(0.5f, 0.0f, 0.0f); glm::vec3 specColor = glm::vec3(1.0f, 1.0f, 1.0f); - const float shininess = 16.0; - const float screenGamma = 2.2; + const float shininess = 5.0; + const float screenGamma = 1.2; glm::vec3 lightDir = normalize(lightPos - fragmentBuffer[index].eyePos); glm::vec3 normal = fragmentBuffer[index].eyeNor; @@ -705,13 +707,14 @@ void _vertexTransformAndAssembly( glm::vec3 eyePos = glm::vec3(MV * glm::vec4(vPos, 0)); VertexOut vOut; - // vOut.pos = glm::vec4(vPos.x, vPos.y, vPos.z, 1); vOut.pos = vOutPos; vOut.eyeNor = glm::vec3(MV * glm::vec4(vNormal,0.0f)); vOut.texcoord0 = vTexcoord; vOut.eyePos = eyePos; vOut.texHeight = primitive.diffuseTexHeight; vOut.texWidth = primitive.diffuseTexWidth; + vOut.dev_diffuseTex = primitive.dev_diffuseTex; + primitive.dev_verticesOut[vid] = vOut; @@ -768,9 +771,12 @@ void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragmen if (iid < numPrimitives) { Primitive triangle = dev_primitives[iid]; - glm::vec3 tri[3] = { glm::vec3(triangle.v[0].pos), - glm::vec3(triangle.v[1].pos), - glm::vec3(triangle.v[2].pos) }; + VertexOut vert0 = triangle.v[0]; + VertexOut vert1 = triangle.v[1]; + VertexOut vert2 = triangle.v[2]; + glm::vec3 tri[3] = { glm::vec3(vert0.pos), + glm::vec3(vert1.pos), + glm::vec3(vert2.pos) }; AABB boundingBox = getAABBForTriangle(tri); for (int y = boundingBox.min.y; y < boundingBox.max.y; y++) { @@ -779,30 +785,27 @@ void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragmen glm::vec3 bary = calculateBarycentricCoordinate(tri, glm::vec2((float)x, (float)y)); if (isBarycentricCoordInBounds(bary)) { // eyePos - glm::vec3 eyePos[3] = { triangle.v[0].eyePos, triangle.v[1].eyePos, triangle.v[2].eyePos }; + glm::vec3 eyePos[3] = { vert0.eyePos, vert1.eyePos, vert2.eyePos }; f.eyePos = barycentricInterpolation(eyePos, bary); // eyeNormals - glm::vec3 eyeNormals[3] = { triangle.v[0].eyeNor, triangle.v[1].eyeNor, triangle.v[2].eyeNor }; + glm::vec3 eyeNormals[3] = { vert0.eyeNor, vert1.eyeNor, vert2.eyeNor }; f.eyeNor = barycentricInterpolation(eyeNormals, bary); // pos glm::vec3 pos = barycentricInterpolation(tri, bary); // textures: - // TODO Perspective correction - glm::vec2 texCoord[3] = { triangle.v[0].texcoord0, triangle.v[1].texcoord0, triangle.v[2].texcoord0 }; - glm::vec2 texCoordinate = glm::vec2(perspectiveInterp(texCoord, bary)); - f.texcoord0 = glm::vec2(texCoordinate.x*triangle.v[0].texWidth, texCoordinate.y * triangle.v[0].texHeight); + glm::vec2 texCoord[3] = { vert0.texcoord0/vert0.pos.z, vert1.texcoord0/vert1.pos.z, vert2.texcoord0/vert2.pos.z }; + glm::vec2 texCoordinate = pos.z * glm::vec2(perspectiveInterp(texCoord, bary)); - //f.texcoord0.x *= triangle.v[0].texWidth; - //f.texcoord0.y *= triangle.v[0].texHeight; + f.texcoord0 = glm::vec2(texCoordinate.x, texCoordinate.y); - f.color = glm::vec3(0.3f, 0.0f, 0.3f); - f.dev_diffuseTex = triangle.v[0].dev_diffuseTex; - f.texWidth = triangle.v[0].texWidth; - f.texHeight = triangle.v[0].texHeight; + f.color = glm::vec3(0.01f, 0.0f, 0.0f); + f.dev_diffuseTex = vert0.dev_diffuseTex; + f.texWidth = vert0.texWidth; + f.texHeight = vert0.texHeight; // Depth Buffering int old = dev_depth[y*width + x]; @@ -830,6 +833,71 @@ void _rasterizeTriangles(int numPrimitives, int numFragments, int width, Fragmen } } +__global__ +void _rasterizePoints(int numPrimitives, int numFragments, int width, Fragment* dev_fragments, Primitive* dev_primitives, int* dev_depth, unsigned int * dev_mutex) { + int iid = (blockIdx.x * blockDim.x) + threadIdx.x; + + if (iid < numPrimitives) { + Primitive triangle = dev_primitives[iid]; + + for (int i = 0; i < 3; i++) { + Fragment f; + int x = triangle.v[i].pos.x; + int y = triangle.v[i].pos.y; + f.color = triangle.v[i].eyeNor; + dev_fragments[y*width + x] = f; + } + + } +} + +__global__ +void _rasterizeLines(int numPrimitives, int numFragments, int width, Fragment* dev_fragments, Primitive* dev_primitives, int* dev_depth, unsigned int * dev_mutex) { + int iid = (blockIdx.x * blockDim.x) + threadIdx.x; + + if (iid < numPrimitives) { + Primitive triangle = dev_primitives[iid]; + for (int i = 0; i < 3; i++) { + Fragment f; + f.color = triangle.v[i].eyeNor; + int x1 = triangle.v[i].pos.x; + int y1 = triangle.v[i].pos.y; + int x2 = triangle.v[(i + 1) % 3].pos.x; + int y2 = triangle.v[(i + 1) % 3].pos.y; + int y = min(y1, y2); + + glm::vec2 p1 = glm::vec2(x1, y1); + glm::vec2 p2 = glm::vec2(x2, y2); + + // swap if necessary + if (x1 > x2) { + glm::vec2 temp = p1; + p1 = p2; + p2 = temp; + } + + // get slope + float m = (float)(p2.y - p1.y) / (float)(p2.x - p1.x); + if (m == INFINITY) { + int ymin = y; + int ymax = max(y1, y2); + for (int qy = ymin; qy < ymax; qy++) { + dev_fragments[y*width + x1] = f; + } + } + else { + int dx = p2.x - p1.x; + for (int dxe = 0; dxe < dx - 1; dxe++) { + int dye = (int)( dxe * m + y); + int index = dye*width + dxe + p1.x; + dev_fragments[index] = f; + } + } + + } + } +} + @@ -887,8 +955,13 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g // TODO: rasterize dim3 numThreadsPerBlock(128); dim3 numBlocksForPrimitives((curPrimitiveBeginId + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); +#if TRIANGLE _rasterizeTriangles << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); - +#elif POINT + _rasterizePoints << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); +#elif LINE + _rasterizeLines << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); +#endif // Copy depthbuffer colors into framebuffer render << > >(width, height, dev_fragmentBuffer, dev_framebuffer); From 7756ca8205e7fdd83734cb47ef3671e8429e8422 Mon Sep 17 00:00:00 2001 From: Wenli Zhao Date: Wed, 18 Oct 2017 22:46:23 -0400 Subject: [PATCH 5/6] added timer and charts --- renders/chart.png | Bin 0 -> 12451 bytes renders/image.png | Bin 0 -> 16964 bytes src/rasterize.cu | 17 +++++++++++ src/rasterize.h | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 renders/chart.png create mode 100644 renders/image.png diff --git a/renders/chart.png b/renders/chart.png new file mode 100644 index 0000000000000000000000000000000000000000..93571602502276db5c42f6221e974cdd96f657c8 GIT binary patch literal 12451 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 literal 0 HcmV?d00001 diff --git a/renders/image.png b/renders/image.png new file mode 100644 index 0000000000000000000000000000000000000000..64bcaf20b2b725946ca2c7c61aad4d4dc07e535f GIT binary patch literal 16964 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 Z{AOw&tb9O%e}~wnqp5$rRKxD^{{fk|^&bEL literal 0 HcmV?d00001 diff --git a/src/rasterize.cu b/src/rasterize.cu index ec65824..6b13074 100644 --- a/src/rasterize.cu +++ b/src/rasterize.cu @@ -104,6 +104,12 @@ namespace { } +PerformanceTimer& timer() +{ + static PerformanceTimer timer; + return timer; +} + static std::map> mesh2PrimitivesMap; @@ -914,6 +920,7 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g // Execute your rasterization pipeline here // (See README for rasterization pipeline outline.) + timer().startCpuTimer(); // Vertex Process & primitive assembly { curPrimitiveBeginId = 0; @@ -948,6 +955,8 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g checkCUDAError("Vertex Processing and Primitive Assembly"); } + timer().endCpuTimer(); + printElapsedTime(timer().getCpuElapsedTimeForPreviousOperation(), "VERTEX ASSEMBLY"); cudaMemset(dev_fragmentBuffer, 0, width * height * sizeof(Fragment)); initDepth << > >(width, height, dev_depth, dev_mutex); @@ -955,6 +964,7 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g // TODO: rasterize dim3 numThreadsPerBlock(128); dim3 numBlocksForPrimitives((curPrimitiveBeginId + numThreadsPerBlock.x - 1) / numThreadsPerBlock.x); + timer().startCpuTimer(); #if TRIANGLE _rasterizeTriangles << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); #elif POINT @@ -962,10 +972,17 @@ void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const g #elif LINE _rasterizeLines << < numBlocksForPrimitives, numThreadsPerBlock >> > (curPrimitiveBeginId, width*height, width, dev_fragmentBuffer, dev_primitives, dev_depth, dev_mutex); #endif + timer().endCpuTimer(); + printElapsedTime(timer().getCpuElapsedTimeForPreviousOperation(), "RASTERIZATION"); + + timer().startCpuTimer(); // Copy depthbuffer colors into framebuffer render << > >(width, height, dev_fragmentBuffer, dev_framebuffer); checkCUDAError("fragment shader"); + timer().endCpuTimer(); + printElapsedTime(timer().getCpuElapsedTimeForPreviousOperation(), "FRAGMENT SHADER"); + // Copy framebuffer into OpenGL buffer for OpenGL previewing sendImageToPBO<<>>(pbo, width, height, dev_framebuffer); checkCUDAError("copy render result to pbo"); diff --git a/src/rasterize.h b/src/rasterize.h index 560aae9..c20c040 100644 --- a/src/rasterize.h +++ b/src/rasterize.h @@ -12,6 +12,9 @@ #include #include +#include +#include + namespace tinygltf{ class Scene; } @@ -22,3 +25,72 @@ void rasterizeSetBuffers(const tinygltf::Scene & scene); void rasterize(uchar4 *pbo, const glm::mat4 & MVP, const glm::mat4 & MV, const glm::mat3 MV_normal); void rasterizeFree(); + +class PerformanceTimer +{ +public: + PerformanceTimer() + { + cudaEventCreate(&event_start); + cudaEventCreate(&event_end); + } + + ~PerformanceTimer() + { + cudaEventDestroy(event_start); + cudaEventDestroy(event_end); + } + + void startCpuTimer() + { + if (cpu_timer_started) { throw std::runtime_error("CPU timer already started"); } + cpu_timer_started = true; + + time_start_cpu = std::chrono::high_resolution_clock::now(); + } + + void endCpuTimer() + { + time_end_cpu = std::chrono::high_resolution_clock::now(); + + if (!cpu_timer_started) { throw std::runtime_error("CPU timer not started"); } + + std::chrono::duration duro = time_end_cpu - time_start_cpu; + prev_elapsed_time_cpu_milliseconds = + static_cast(duro.count()); + + cpu_timer_started = false; + } + + float getCpuElapsedTimeForPreviousOperation() //noexcept //(damn I need VS 2015 + { + return prev_elapsed_time_cpu_milliseconds; + } + + + // remove copy and move functions + PerformanceTimer(const PerformanceTimer&) = delete; + PerformanceTimer(PerformanceTimer&&) = delete; + PerformanceTimer& operator=(const PerformanceTimer&) = delete; + PerformanceTimer& operator=(PerformanceTimer&&) = delete; + +private: + cudaEvent_t event_start = nullptr; + cudaEvent_t event_end = nullptr; + + using time_point_t = std::chrono::high_resolution_clock::time_point; + time_point_t time_start_cpu; + time_point_t time_end_cpu; + + bool cpu_timer_started = false; + + float prev_elapsed_time_cpu_milliseconds = 0.f; +}; + +PerformanceTimer& timer(); + +template +void printElapsedTime(T time, std::string note = "") +{ + std::cout << " elapsed time: " << time << "ms " << note << std::endl; +} \ No newline at end of file From 725b7a415dec7aa7613b7e388d9ed8b15e0058be Mon Sep 17 00:00:00 2001 From: wpchop Date: Wed, 18 Oct 2017 23:02:48 -0400 Subject: [PATCH 6/6] Update README.md --- README.md | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cad1abd..88716e0 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,46 @@ CUDA Rasterizer =============== -[CLICK ME FOR INSTRUCTION OF THIS PROJECT](./INSTRUCTION.md) **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 4** -* (TODO) YOUR NAME HERE -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Wenli Zhao +* Tested on: Windows 10 Pro, Intel Xeon CPU CPU E5-1630 v4 @ 3.70GHz 32GB, NVIDIA GeForce GTX 24465MB (Sig Lab) -### (TODO: Your README) +### README -*DO NOT* leave the README to the last minute! It is a crucial part of the -project, and we will not be able to grade you without a good README. +![](renders/Capture2.PNG) +In this project, I implemented a simplified graphics rasterizer pipeline which includes vertex shading, primitive assembly, rasterization, fragment shading, and a framebuffer. + +The core features I implemented included: +* Vertex shading. +* Primitive assembly with support for triangles read from buffers of index and + vertex data. +* Rasterization. +* Fragment shading. +* A depth buffer for storing and depth testing fragments. +* Fragment-to-depth-buffer writing with atomics +* A fragment shader with simple Blinn-Phong lighting scheme. + +In addition to the basic rasterizer, I implemented UV texture mapping and support for rasterization with points and lines. + +#### Texture Mapping +![](renders/Capture3.PNG) + +#### Points +![](renders/points.PNG) + +#### Lines +![](renders/lines.PNG) + +### Analysis + +![](renders/chart.png) + +![](renders/image.png) + +The features I implemented didn't have too much of a performance impact on the models I tested. For example, the first three bars of the chart have a similar distribution. For rasterization of points and lines, I didn't change vertex assembly very much, so the bottleneck remained there. Vertex assembly contains a lot of global memory calls that slow down the pipeline. In general, the fragment shading and rasterization were pretty quick. I think I might have corrupted the cow model since it gave a very different distribution. I'm still not exactly sure why. There is a lot more I could do to accelerate various parts of the rasterization pipeline. I could potentially use shared memory for texture sampling and used tile-based rendering to accelerate my pipeline. ### Credits