WIP on canvas pixel shading
This commit is contained in:
parent
fb3d32baf4
commit
2aeecdec62
24 changed files with 317 additions and 83 deletions
|
@ -99,3 +99,8 @@ void CanvasPixel::updateComposite()
|
||||||
}
|
}
|
||||||
composite = result;
|
composite = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CanvasPixel::setComposite(const Color &color)
|
||||||
|
{
|
||||||
|
composite = color;
|
||||||
|
}
|
||||||
|
|
|
@ -22,11 +22,13 @@ public:
|
||||||
|
|
||||||
inline int getFragmentCount() const {return count;}
|
inline int getFragmentCount() const {return count;}
|
||||||
inline const Color &getComposite() const {return composite;}
|
inline const Color &getComposite() const {return composite;}
|
||||||
|
inline const CanvasFragment &getFragment(int position) const {return fragments[position];}
|
||||||
const CanvasFragment *getFrontFragment() const;
|
const CanvasFragment *getFrontFragment() const;
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void pushFragment(const CanvasFragment &fragment);
|
void pushFragment(const CanvasFragment &fragment);
|
||||||
void updateComposite();
|
void updateComposite();
|
||||||
|
void setComposite(const Color &color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int count;
|
int count;
|
||||||
|
|
36
src/render/software/CanvasPixelShader.cpp
Normal file
36
src/render/software/CanvasPixelShader.cpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#include "CanvasPixelShader.h"
|
||||||
|
|
||||||
|
#include "Color.h"
|
||||||
|
#include "SoftwareCanvasRenderer.h"
|
||||||
|
#include "CanvasPortion.h"
|
||||||
|
#include "CanvasPixel.h"
|
||||||
|
#include "CanvasFragment.h"
|
||||||
|
#include "Rasterizer.h"
|
||||||
|
|
||||||
|
CanvasPixelShader::CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y):
|
||||||
|
renderer(renderer), portion(portion), chunk_size(chunk_size), chunks_x(chunks_x), chunks_y(chunks_y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int CanvasPixelShader::processParallelUnit(int unit)
|
||||||
|
{
|
||||||
|
// Locate the chunk we work on
|
||||||
|
int chunk_x = unit % chunks_x;
|
||||||
|
int chunk_y = unit / chunks_x;
|
||||||
|
|
||||||
|
// Resolve the pixel color
|
||||||
|
int x = chunk_x * chunk_size;
|
||||||
|
int y = chunk_y * chunk_size;
|
||||||
|
const CanvasPixel &pixel = portion->at(x, y);
|
||||||
|
int n = pixel.getFragmentCount();
|
||||||
|
Color composite = COLOR_BLACK;
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
const CanvasFragment &fragment = pixel.getFragment(i);
|
||||||
|
const Rasterizer &rasterizer = renderer.getRasterizer(fragment.getClient());
|
||||||
|
composite.mask(rasterizer.shadeFragment(fragment));
|
||||||
|
}
|
||||||
|
portion->setColor(x, y, composite);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
36
src/render/software/CanvasPixelShader.h
Normal file
36
src/render/software/CanvasPixelShader.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifndef CANVASPIXELSHADER_H
|
||||||
|
#define CANVASPIXELSHADER_H
|
||||||
|
|
||||||
|
#include "software_global.h"
|
||||||
|
|
||||||
|
#include "ParallelWorker.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace software {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parallel worker that can work on canvas portion to resolve pixel colors.
|
||||||
|
*
|
||||||
|
* This is used after the rasterization phase to compute pixel colors from the fragments stored in them.
|
||||||
|
*
|
||||||
|
* This worker will be set to work on a given chunk of a canvas portion.
|
||||||
|
*/
|
||||||
|
class CanvasPixelShader: public ParallelWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CanvasPixelShader(const SoftwareCanvasRenderer &renderer, CanvasPortion *portion, int chunk_size, int chunks_x, int chunks_y);
|
||||||
|
|
||||||
|
virtual int processParallelUnit(int unit);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const SoftwareCanvasRenderer &renderer;
|
||||||
|
CanvasPortion *portion;
|
||||||
|
int chunk_size;
|
||||||
|
int chunks_x;
|
||||||
|
int chunks_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CANVASPIXELSHADER_H
|
|
@ -69,3 +69,25 @@ void CanvasPortion::pushFragment(int x, int y, const CanvasFragment &fragment)
|
||||||
preview->pushPixel(x, y, old_color, pixel.getComposite());
|
preview->pushPixel(x, y, old_color, pixel.getComposite());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CanvasPixel &CanvasPortion::at(int x, int y)
|
||||||
|
{
|
||||||
|
CHECK_COORDINATES();
|
||||||
|
|
||||||
|
return pixels[y * width + x];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CanvasPortion::setColor(int x, int y, const Color &color)
|
||||||
|
{
|
||||||
|
CHECK_COORDINATES();
|
||||||
|
|
||||||
|
CanvasPixel &pixel = pixels[y * width + x];
|
||||||
|
Color old_color = pixel.getComposite();
|
||||||
|
|
||||||
|
pixel.setComposite(color);
|
||||||
|
|
||||||
|
if (preview)
|
||||||
|
{
|
||||||
|
preview->pushPixel(x, y, old_color, pixel.getComposite());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ namespace paysages {
|
||||||
namespace software {
|
namespace software {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Rectangular portion of a Canvas.
|
* Rectangular portion of a Canvas.
|
||||||
*
|
*
|
||||||
* Contains the pixels of a canvas region (CanvasPixel).
|
* Contains the pixels of a canvas region (CanvasPixel).
|
||||||
*/
|
*/
|
||||||
|
@ -26,12 +26,26 @@ public:
|
||||||
void setSize(int width, int height);
|
void setSize(int width, int height);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a fragment to the pixel located at (x, y).
|
* Add a fragment to the pixel located at (x, y).
|
||||||
*
|
*
|
||||||
* Checking x and y coordinates to be in the canvas portion should be done before this call.
|
* Checking x and y coordinates to be in the canvas portion should be done before this call.
|
||||||
*/
|
*/
|
||||||
void pushFragment(int x, int y, const CanvasFragment &fragment);
|
void pushFragment(int x, int y, const CanvasFragment &fragment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the CanvasPixel at a given coordinates.
|
||||||
|
*
|
||||||
|
* Checking x and y coordinates to be in the canvas portion should be done before this call.
|
||||||
|
*/
|
||||||
|
const CanvasPixel &at(int x, int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the final color of the pixel.
|
||||||
|
*
|
||||||
|
* Checking x and y coordinates to be in the canvas portion should be done before this call.
|
||||||
|
*/
|
||||||
|
void setColor(int x, int y, const Color &color);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
|
|
|
@ -136,10 +136,6 @@ void Rasterizer::pushDisplacedQuad(CanvasPortion *canvas, const Vector3 &v1, con
|
||||||
pushDisplacedTriangle(canvas, v4, v1, v3, ov4, ov1, ov3);
|
pushDisplacedTriangle(canvas, v4, v1, v3, ov4, ov1, ov3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rasterizer::rasterizeToCanvas(CanvasPortion *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Rasterizer::scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result)
|
void Rasterizer::scanGetDiff(ScanPoint* v1, ScanPoint* v2, ScanPoint* result)
|
||||||
{
|
{
|
||||||
result->pixel.x = v2->pixel.x - v1->pixel.x;
|
result->pixel.x = v2->pixel.x - v1->pixel.x;
|
||||||
|
@ -315,6 +311,13 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin
|
||||||
|
|
||||||
current.x = x;
|
current.x = x;
|
||||||
for (cury = starty; cury <= endy; cury++)
|
for (cury = starty; cury <= endy; cury++)
|
||||||
|
{
|
||||||
|
if (dy == 0)
|
||||||
|
{
|
||||||
|
// Down and up are the same
|
||||||
|
current = down;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
fy = (double)cury + 0.5;
|
fy = (double)cury + 0.5;
|
||||||
if (fy < down.pixel.y)
|
if (fy < down.pixel.y)
|
||||||
|
@ -329,12 +332,15 @@ void Rasterizer::renderScanLines(CanvasPortion *canvas, RenderScanlines* scanlin
|
||||||
|
|
||||||
current.y = cury;
|
current.y = cury;
|
||||||
scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t);
|
scanInterpolate(renderer->render_camera, &down, &diff, fy / dy, ¤t);
|
||||||
|
}
|
||||||
|
|
||||||
CanvasFragment fragment(current.pixel.z, Vector3(current.location.x, current.location.y, current.location.z), current.client);
|
CanvasFragment fragment(current.pixel.z, Vector3(current.location.x, current.location.y, current.location.z), current.client);
|
||||||
|
|
||||||
Color frag_color = *color;
|
Color frag_color = *color;
|
||||||
if (cury == starty || cury == endy)
|
if (cury == starty || cury == endy)
|
||||||
|
{
|
||||||
frag_color.mask(Color(0.0, 0.0, 0.0, 0.3));
|
frag_color.mask(Color(0.0, 0.0, 0.0, 0.3));
|
||||||
|
}
|
||||||
fragment.setColor(frag_color);
|
fragment.setColor(frag_color);
|
||||||
|
|
||||||
canvas->pushFragment(current.x, current.y, fragment);
|
canvas->pushFragment(current.x, current.y, fragment);
|
||||||
|
|
|
@ -20,7 +20,8 @@ public:
|
||||||
|
|
||||||
inline SoftwareRenderer *getRenderer() const {return renderer;}
|
inline SoftwareRenderer *getRenderer() const {return renderer;}
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
virtual void rasterizeToCanvas(CanvasPortion* canvas) = 0;
|
||||||
|
virtual Color shadeFragment(const CanvasFragment &fragment) const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3);
|
void pushProjectedTriangle(CanvasPortion *canvas, const Vector3 &pixel1, const Vector3 &pixel2, const Vector3 &pixel3, const Vector3 &location1, const Vector3 &location2, const Vector3 &location3);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "AtmosphereResult.h"
|
#include "AtmosphereResult.h"
|
||||||
#include "CloudsRenderer.h"
|
#include "CloudsRenderer.h"
|
||||||
#include "Rasterizer.h"
|
#include "Rasterizer.h"
|
||||||
|
#include "CanvasFragment.h"
|
||||||
|
|
||||||
#define SPHERE_SIZE 20000.0
|
#define SPHERE_SIZE 20000.0
|
||||||
|
|
||||||
|
@ -15,21 +16,6 @@ SkyRasterizer::SkyRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &location, void*)
|
|
||||||
{
|
|
||||||
Vector3 camera_location, direction;
|
|
||||||
Color result;
|
|
||||||
|
|
||||||
camera_location = renderer->getCameraLocation(location);
|
|
||||||
direction = location.sub(camera_location);
|
|
||||||
|
|
||||||
/* TODO Don't compute result->color if it's fully covered by clouds */
|
|
||||||
result = renderer->getAtmosphereRenderer()->getSkyColor(direction.normalize()).final;
|
|
||||||
result = renderer->getCloudsRenderer()->getColor(camera_location, camera_location.add(direction.scale(10.0)), result);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
||||||
{
|
{
|
||||||
int res_i, res_j;
|
int res_i, res_j;
|
||||||
|
@ -84,3 +70,19 @@ void SkyRasterizer::rasterizeToCanvas(CanvasPortion* canvas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color SkyRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
||||||
|
{
|
||||||
|
Vector3 location = fragment.getLocation();
|
||||||
|
Vector3 camera_location, direction;
|
||||||
|
Color result;
|
||||||
|
|
||||||
|
camera_location = renderer->getCameraLocation(location);
|
||||||
|
direction = location.sub(camera_location);
|
||||||
|
|
||||||
|
/* TODO Don't compute result->color if it's fully covered by clouds */
|
||||||
|
result = renderer->getAtmosphereRenderer()->getSkyColor(direction.normalize()).final;
|
||||||
|
result = renderer->getCloudsRenderer()->getColor(camera_location, camera_location.add(direction.scale(10.0)), result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ public:
|
||||||
SkyRasterizer(SoftwareRenderer* renderer, int client_id);
|
SkyRasterizer(SoftwareRenderer* renderer, int client_id);
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
||||||
|
virtual Color shadeFragment(const CanvasFragment &fragment) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
#include "WaterRasterizer.h"
|
#include "WaterRasterizer.h"
|
||||||
#include "SkyRasterizer.h"
|
#include "SkyRasterizer.h"
|
||||||
#include "CameraDefinition.h"
|
#include "CameraDefinition.h"
|
||||||
|
#include "ParallelWork.h"
|
||||||
|
#include "CanvasPortion.h"
|
||||||
|
#include "CanvasPixelShader.h"
|
||||||
|
|
||||||
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
|
SoftwareCanvasRenderer::SoftwareCanvasRenderer()
|
||||||
{
|
{
|
||||||
|
@ -58,6 +61,11 @@ const std::vector<Rasterizer *> &SoftwareCanvasRenderer::getRasterizers() const
|
||||||
return rasterizers;
|
return rasterizers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Rasterizer &SoftwareCanvasRenderer::getRasterizer(int client_id) const
|
||||||
|
{
|
||||||
|
return *(getRasterizers()[client_id]);
|
||||||
|
}
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded)
|
void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded)
|
||||||
{
|
{
|
||||||
for (auto &rasterizer:getRasterizers())
|
for (auto &rasterizer:getRasterizers())
|
||||||
|
@ -68,5 +76,14 @@ void SoftwareCanvasRenderer::rasterize(CanvasPortion *portion, bool threaded)
|
||||||
|
|
||||||
void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded)
|
void SoftwareCanvasRenderer::postProcess(CanvasPortion *portion, bool threaded)
|
||||||
{
|
{
|
||||||
// TODO
|
// Subdivide in chunks
|
||||||
|
int chunk_size = 32;
|
||||||
|
int chunks_x = portion->getWidth() / chunk_size + 1;
|
||||||
|
int chunks_y = portion->getHeight() / chunk_size + 1;
|
||||||
|
int units = chunks_x * chunks_y;
|
||||||
|
|
||||||
|
// Render chunks in parallel
|
||||||
|
CanvasPixelShader shader(*this, portion, chunk_size, chunks_x, chunks_y);
|
||||||
|
ParallelWork work(&shader, units);
|
||||||
|
work.perform();
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,16 @@ public:
|
||||||
*/
|
*/
|
||||||
void render();
|
void render();
|
||||||
|
|
||||||
/*!
|
/**
|
||||||
* \brief Get the list of objects that can be rasterized to polygons on a canvas.
|
* @brief Get the list of objects that can be rasterized to polygons on a canvas.
|
||||||
*/
|
*/
|
||||||
virtual const std::vector<Rasterizer*> &getRasterizers() const;
|
virtual const std::vector<Rasterizer*> &getRasterizers() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a rasterizer by its client id.
|
||||||
|
*/
|
||||||
|
const Rasterizer &getRasterizer(int client_id) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Rasterize the scenery into a canvas portion.
|
* @brief Rasterize the scenery into a canvas portion.
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "Scenery.h"
|
#include "Scenery.h"
|
||||||
#include "ParallelQueue.h"
|
#include "ParallelQueue.h"
|
||||||
#include "CanvasPortion.h"
|
#include "CanvasPortion.h"
|
||||||
|
#include "CanvasFragment.h"
|
||||||
|
|
||||||
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id):
|
TerrainRasterizer::TerrainRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
Rasterizer(renderer, client_id, Color(0.5, 0.3, 0.3))
|
Rasterizer(renderer, client_id, Color(0.5, 0.3, 0.3))
|
||||||
|
@ -20,12 +21,6 @@ static inline Vector3 _getPoint(SoftwareRenderer* renderer, double x, double z)
|
||||||
return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, 1), z);
|
return Vector3(x, renderer->getTerrainRenderer()->getHeight(x, z, 1), z);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &point, void*)
|
|
||||||
{
|
|
||||||
double precision = renderer->getPrecision(_getPoint(renderer, point.x, point.z));
|
|
||||||
return renderer->getTerrainRenderer()->getFinalColor(point, precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail)
|
void TerrainRasterizer::tessellateChunk(CanvasPortion* canvas, TerrainChunkInfo* chunk, int detail)
|
||||||
{
|
{
|
||||||
if (detail < 1)
|
if (detail < 1)
|
||||||
|
@ -245,3 +240,10 @@ void TerrainRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
|
|
||||||
queue->wait();
|
queue->wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color TerrainRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
||||||
|
{
|
||||||
|
Vector3 point = fragment.getLocation();
|
||||||
|
double precision = renderer->getPrecision(_getPoint(renderer, point.x, point.z));
|
||||||
|
return renderer->getTerrainRenderer()->getFinalColor(point, precision);
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
virtual void rasterize();
|
virtual void rasterize();
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
||||||
|
virtual Color shadeFragment(const CanvasFragment &fragment) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ParallelQueue* queue;
|
ParallelQueue* queue;
|
||||||
|
|
|
@ -3,17 +3,13 @@
|
||||||
#include "SoftwareRenderer.h"
|
#include "SoftwareRenderer.h"
|
||||||
#include "WaterRenderer.h"
|
#include "WaterRenderer.h"
|
||||||
#include "ParallelQueue.h"
|
#include "ParallelQueue.h"
|
||||||
|
#include "CanvasFragment.h"
|
||||||
|
|
||||||
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id):
|
WaterRasterizer::WaterRasterizer(SoftwareRenderer* renderer, int client_id):
|
||||||
Rasterizer(renderer, client_id, Color(0.1, 0.3, 0.6))
|
Rasterizer(renderer, client_id, Color(0.1, 0.3, 0.6))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static Color _postProcessFragment(SoftwareRenderer* renderer, const Vector3 &location, void*)
|
|
||||||
{
|
|
||||||
return renderer->getWaterRenderer()->getResult(location.x, location.z).final;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, double z)
|
static inline Vector3 _getFirstPassVertex(SoftwareRenderer* renderer, double x, double z)
|
||||||
{
|
{
|
||||||
Vector3 result;
|
Vector3 result;
|
||||||
|
@ -84,3 +80,9 @@ void WaterRasterizer::rasterizeToCanvas(CanvasPortion *canvas)
|
||||||
radius_ext += chunk_size;
|
radius_ext += chunk_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color WaterRasterizer::shadeFragment(const CanvasFragment &fragment) const
|
||||||
|
{
|
||||||
|
Vector3 location = fragment.getLocation();
|
||||||
|
return renderer->getWaterRenderer()->getResult(location.x, location.z).final;
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ public:
|
||||||
void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size);
|
void rasterizeQuad(CanvasPortion* canvas, double x, double z, double size);
|
||||||
|
|
||||||
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
virtual void rasterizeToCanvas(CanvasPortion* canvas);
|
||||||
|
virtual Color shadeFragment(const CanvasFragment &fragment) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ SOURCES += SoftwareRenderer.cpp \
|
||||||
Rasterizer.cpp \
|
Rasterizer.cpp \
|
||||||
CanvasLiveClient.cpp \
|
CanvasLiveClient.cpp \
|
||||||
CanvasPreview.cpp \
|
CanvasPreview.cpp \
|
||||||
RenderConfig.cpp
|
RenderConfig.cpp \
|
||||||
|
CanvasPixelShader.cpp
|
||||||
|
|
||||||
HEADERS += SoftwareRenderer.h\
|
HEADERS += SoftwareRenderer.h\
|
||||||
software_global.h \
|
software_global.h \
|
||||||
|
@ -80,7 +81,8 @@ HEADERS += SoftwareRenderer.h\
|
||||||
Rasterizer.h \
|
Rasterizer.h \
|
||||||
CanvasLiveClient.h \
|
CanvasLiveClient.h \
|
||||||
CanvasPreview.h \
|
CanvasPreview.h \
|
||||||
RenderConfig.h
|
RenderConfig.h \
|
||||||
|
CanvasPixelShader.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -53,6 +53,7 @@ namespace software {
|
||||||
class CanvasFragment;
|
class CanvasFragment;
|
||||||
class CanvasLiveClient;
|
class CanvasLiveClient;
|
||||||
class CanvasPreview;
|
class CanvasPreview;
|
||||||
|
class CanvasPixelShader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,37 +2,72 @@
|
||||||
|
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
#include "System.h"
|
#include "System.h"
|
||||||
|
#include "ParallelWorker.h"
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compatibility class for code that uses ParallelUnitFunction.
|
||||||
|
*/
|
||||||
|
class ParallelWorkerCompat:public ParallelWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParallelWorkerCompat(ParallelWork *work, ParallelWork::ParallelUnitFunction func, void* data):
|
||||||
|
ParallelWorker(), work(work), func(func), data(data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int processParallelUnit(int unit)
|
||||||
|
{
|
||||||
|
return func(work, unit, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParallelWork* work;
|
||||||
|
ParallelWork::ParallelUnitFunction func;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
ParallelWork::ParallelWork(ParallelWorker *worker, int units)
|
||||||
|
{
|
||||||
|
this->units = units;
|
||||||
|
this->running = 0;
|
||||||
|
this->worker = worker;
|
||||||
|
this->worker_compat = false;
|
||||||
|
}
|
||||||
|
|
||||||
ParallelWork::ParallelWork(ParallelUnitFunction func, int units, void* data)
|
ParallelWork::ParallelWork(ParallelUnitFunction func, int units, void* data)
|
||||||
{
|
{
|
||||||
this->units = units;
|
this->units = units;
|
||||||
this->running = 0;
|
this->running = 0;
|
||||||
this->unit_function = func;
|
this->worker = new ParallelWorkerCompat(this, func, data);
|
||||||
this->data = data;
|
this->worker_compat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ParallelWork::~ParallelWork()
|
ParallelWork::~ParallelWork()
|
||||||
{
|
{
|
||||||
assert(not running);
|
assert(not running);
|
||||||
|
if (worker_compat)
|
||||||
|
{
|
||||||
|
delete worker;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* _workerThreadCallback(ParallelWork::ParallelWorker* worker)
|
static void* _workerThreadCallback(ParallelWork::ParallelWorkerThread* thread)
|
||||||
{
|
{
|
||||||
worker->result = worker->work->unit_function(worker->work, worker->unit, worker->work->data);
|
thread->result = thread->worker->processParallelUnit(thread->unit);
|
||||||
worker->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE;
|
thread->status = ParallelWork::PARALLEL_WORKER_STATUS_DONE;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _runNextWorker(ParallelWork::ParallelWorker workers[], int worker_count, int unit)
|
static int _runNextWorker(ParallelWork::ParallelWorkerThread threads[], int thread_count, int unit)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
for (i = 0; i < worker_count; i++)
|
for (i = 0; i < thread_count; i++)
|
||||||
{
|
{
|
||||||
ParallelWork::ParallelWorker* worker = workers + i;
|
ParallelWork::ParallelWorkerThread* worker = threads + i;
|
||||||
if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_VOID)
|
if (worker->status == ParallelWork::PARALLEL_WORKER_STATUS_VOID)
|
||||||
{
|
{
|
||||||
worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING;
|
worker->status = ParallelWork::PARALLEL_WORKER_STATUS_RUNNING;
|
||||||
|
@ -62,47 +97,47 @@ static int _runNextWorker(ParallelWork::ParallelWorker workers[], int worker_cou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ParallelWork::perform(int nbworkers)
|
int ParallelWork::perform(int thread_count)
|
||||||
{
|
{
|
||||||
int i, done, result;
|
int i, done, result;
|
||||||
assert(not running);
|
assert(not running);
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
|
|
||||||
if (nbworkers <= 0)
|
if (thread_count <= 0)
|
||||||
{
|
{
|
||||||
nbworkers = System::getCoreCount();
|
thread_count = System::getCoreCount();
|
||||||
}
|
}
|
||||||
if (nbworkers > PARALLEL_MAX_THREADS)
|
if (thread_count > PARALLEL_MAX_THREADS)
|
||||||
{
|
{
|
||||||
nbworkers = PARALLEL_MAX_THREADS;
|
thread_count = PARALLEL_MAX_THREADS;
|
||||||
}
|
}
|
||||||
running = 1;
|
running = 1;
|
||||||
|
|
||||||
/* Init workers */
|
/* Init workers */
|
||||||
for (i = 0; i < nbworkers; i++)
|
for (i = 0; i < thread_count; i++)
|
||||||
{
|
{
|
||||||
workers[i].status = PARALLEL_WORKER_STATUS_VOID;
|
threads[i].status = PARALLEL_WORKER_STATUS_VOID;
|
||||||
workers[i].work = this;
|
threads[i].worker = worker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform run */
|
/* Perform run */
|
||||||
for (done = 0; done < units; done++)
|
for (done = 0; done < units; done++)
|
||||||
{
|
{
|
||||||
if (_runNextWorker(workers, nbworkers, done))
|
if (_runNextWorker(threads, thread_count, done))
|
||||||
{
|
{
|
||||||
result++;
|
result++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Wait and clean up workers */
|
/* Wait and clean up workers */
|
||||||
for (i = 0; i < nbworkers; i++)
|
for (i = 0; i < thread_count; i++)
|
||||||
{
|
{
|
||||||
if (workers[i].status != PARALLEL_WORKER_STATUS_VOID)
|
if (threads[i].status != PARALLEL_WORKER_STATUS_VOID)
|
||||||
{
|
{
|
||||||
workers[i].thread->join();
|
threads[i].thread->join();
|
||||||
delete workers[i].thread;
|
delete threads[i].thread;
|
||||||
if (workers[i].result)
|
if (threads[i].result)
|
||||||
{
|
{
|
||||||
result++;
|
result++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,22 +23,24 @@ public:
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
ParallelWork* work;
|
ParallelWorker* worker;
|
||||||
ParallelWorkerStatus status;
|
ParallelWorkerStatus status;
|
||||||
int unit;
|
int unit;
|
||||||
int result;
|
int result;
|
||||||
} ParallelWorker;
|
} ParallelWorkerThread;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a parallel work handler.
|
* Create a parallel work handler.
|
||||||
*
|
*
|
||||||
* This will spawn an optimal number of threads to process a given number of work units.
|
* This will spawn a number of threads.
|
||||||
|
*/
|
||||||
|
ParallelWork(ParallelWorker *worker, int units);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a parallel work handler.
|
||||||
*
|
*
|
||||||
* @param func The callback that will be called from threads to process one unit.
|
* This is a compatibility constructor for older code, use the constructor with ParallelWorker instead.
|
||||||
* @param units Number of units to handle.
|
|
||||||
* @param data Custom data that will be passed to the callback.
|
|
||||||
* @return The newly allocated handler.
|
|
||||||
*/
|
*/
|
||||||
ParallelWork(ParallelUnitFunction func, int units, void* data);
|
ParallelWork(ParallelUnitFunction func, int units, void* data);
|
||||||
|
|
||||||
|
@ -52,15 +54,15 @@ public:
|
||||||
/**
|
/**
|
||||||
* Start working on the units.
|
* Start working on the units.
|
||||||
*
|
*
|
||||||
* @param workers Number of threads to spaws, -1 for an optimal number.
|
* @param threads Number of threads to spaws, -1 for an optimal number.
|
||||||
*/
|
*/
|
||||||
int perform(int workers=-1);
|
int perform(int thread_count=-1);
|
||||||
|
|
||||||
int units;
|
int units;
|
||||||
int running;
|
int running;
|
||||||
ParallelUnitFunction unit_function;
|
ParallelWorker *worker;
|
||||||
ParallelWorker workers[PARALLEL_MAX_THREADS];
|
bool worker_compat;
|
||||||
void* data;
|
ParallelWorkerThread threads[PARALLEL_MAX_THREADS];
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
9
src/system/ParallelWorker.cpp
Normal file
9
src/system/ParallelWorker.cpp
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#include "ParallelWorker.h"
|
||||||
|
|
||||||
|
ParallelWorker::ParallelWorker()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ParallelWorker::~ParallelWorker()
|
||||||
|
{
|
||||||
|
}
|
29
src/system/ParallelWorker.h
Normal file
29
src/system/ParallelWorker.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef PARALLELWORKER_H
|
||||||
|
#define PARALLELWORKER_H
|
||||||
|
|
||||||
|
#include "system_global.h"
|
||||||
|
|
||||||
|
namespace paysages {
|
||||||
|
namespace system {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Worker that can be used by the ParallelWork object to perform tasks in several threads.
|
||||||
|
*/
|
||||||
|
class SYSTEMSHARED_EXPORT ParallelWorker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ParallelWorker();
|
||||||
|
virtual ~ParallelWorker();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to reimplement to process a work unit.
|
||||||
|
*
|
||||||
|
* This method will be called from any thread in the thread pool used by the ParallelWork.
|
||||||
|
*/
|
||||||
|
virtual int processParallelUnit(int unit) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PARALLELWORKER_H
|
|
@ -25,7 +25,8 @@ SOURCES += \
|
||||||
CacheFile.cpp \
|
CacheFile.cpp \
|
||||||
PictureWriter.cpp \
|
PictureWriter.cpp \
|
||||||
Logs.cpp \
|
Logs.cpp \
|
||||||
ParallelPool.cpp
|
ParallelPool.cpp \
|
||||||
|
ParallelWorker.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
system_global.h \
|
system_global.h \
|
||||||
|
@ -40,7 +41,8 @@ HEADERS += \
|
||||||
CacheFile.h \
|
CacheFile.h \
|
||||||
PictureWriter.h \
|
PictureWriter.h \
|
||||||
Logs.h \
|
Logs.h \
|
||||||
ParallelPool.h
|
ParallelPool.h \
|
||||||
|
ParallelWorker.h
|
||||||
|
|
||||||
unix:!symbian {
|
unix:!symbian {
|
||||||
maemo5 {
|
maemo5 {
|
||||||
|
|
|
@ -18,6 +18,7 @@ namespace system {
|
||||||
class ParallelQueue;
|
class ParallelQueue;
|
||||||
class ParallelWork;
|
class ParallelWork;
|
||||||
class ParallelPool;
|
class ParallelPool;
|
||||||
|
class ParallelWorker;
|
||||||
class Thread;
|
class Thread;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue