aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu
diff options
context:
space:
mode:
authorGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-07-11 16:01:22 +0000
committerGravatar senorblanco@chromium.org <senorblanco@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-07-11 16:01:22 +0000
commit894790d77c56cd4bae8070331d275c6d2897e33c (patch)
tree3eb922a14915b4a54f5788b323ae6d2c6c80fe45 /src/gpu
parenteb715c8d5caa2191d611c4f9cfb22b4afc6c8d02 (diff)
This patch implements the diffuse and specular lighting filters in Ganesh.
There are three light types for each: distant, point and spot, whose code generation lives in a GrGLLight class hierarchy. This similar to the CPU implementation, where each light type provides a function to compute the vector from the surface plane to the light (surfaceToLight) and to compute the light colour (emitLightColour). Instead of templated member functions, as in the CPU implementation, these are virtual functions to emit the light-specific GLSL code. All of the code for the GPU path lives in the same file as that for the CPU path, SkLightingImageFilter.cpp. In order to provide Ganesh a hook to access it, SkImageFilter now has a asNewCustomStage() virtual, which allows an image filter to return a GrCustomStage representing that filter. Note that this patch does not handle the border conditions correctly (the [top|bottom][Left|Right]Normal() functions in the CPU implementation). That will come in a future patch. Review URL: http://codereview.appspot.com/6345081/ git-svn-id: http://skia.googlecode.com/svn/trunk@4535 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r--src/gpu/SkGpuDevice.cpp43
-rw-r--r--src/gpu/gl/GrGpuGL_unittest.cpp91
2 files changed, 131 insertions, 3 deletions
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index fc73f0d020..e5227a275b 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1424,6 +1424,33 @@ void SkGpuDevice::internalDrawBitmap(const SkDraw& draw,
fContext->drawRectToRect(*grPaint, dstRect, paintRect, &m);
}
+namespace {
+
+void apply_custom_stage(GrContext* context,
+ GrTexture* srcTexture,
+ GrTexture* dstTexture,
+ const GrRect& rect,
+ GrCustomStage* stage) {
+ SkASSERT(srcTexture && srcTexture->getContext() == context);
+ GrAutoMatrix avm(context, GrMatrix::I());
+ GrContext::AutoRenderTarget art(context, dstTexture->asRenderTarget());
+ GrClip oldClip = context->getClip();
+ context->setClip(rect);
+
+ GrMatrix sampleM;
+ sampleM.setIDiv(srcTexture->width(), srcTexture->height());
+ GrPaint paint;
+ paint.reset();
+ paint.textureSampler(0)->setFilter(GrSamplerState::kBilinear_Filter);
+ paint.textureSampler(0)->reset(sampleM);
+ paint.textureSampler(0)->setCustomStage(stage);
+ paint.setTexture(0, srcTexture);
+ context->drawRect(paint, rect);
+ context->setClip(oldClip);
+}
+
+};
+
static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
SkImageFilter* filter, const GrRect& rect) {
GrAssert(filter);
@@ -1436,8 +1463,14 @@ static GrTexture* filter_texture(GrContext* context, GrTexture* texture,
desc.fWidth = SkScalarCeilToInt(rect.width());
desc.fHeight = SkScalarCeilToInt(rect.height());
desc.fConfig = kRGBA_8888_PM_GrPixelConfig;
-
- if (filter->asABlur(&blurSize)) {
+ GrCustomStage* stage;
+
+ if (filter->asNewCustomStage(&stage)) {
+ GrAutoScratchTexture dst(context, desc);
+ apply_custom_stage(context, texture, dst.texture(), rect, stage);
+ texture = dst.detach();
+ stage->unref();
+ } else if (filter->asABlur(&blurSize)) {
GrAutoScratchTexture temp1, temp2;
texture = context->gaussianBlur(texture, &temp1, &temp2, rect,
blurSize.width(),
@@ -1564,7 +1597,11 @@ void SkGpuDevice::drawDevice(const SkDraw& draw, SkDevice* device,
bool SkGpuDevice::canHandleImageFilter(SkImageFilter* filter) {
SkSize size;
SkISize radius;
- if (!filter->asABlur(&size) && !filter->asADilate(&radius) && !filter->asAnErode(&radius)) {
+
+ if (!filter->asNewCustomStage(NULL) &&
+ !filter->asABlur(&size) &&
+ !filter->asADilate(&radius) &&
+ !filter->asAnErode(&radius)) {
return false;
}
return true;
diff --git a/src/gpu/gl/GrGpuGL_unittest.cpp b/src/gpu/gl/GrGpuGL_unittest.cpp
index 7f71f48203..82804450b0 100644
--- a/src/gpu/gl/GrGpuGL_unittest.cpp
+++ b/src/gpu/gl/GrGpuGL_unittest.cpp
@@ -3,6 +3,7 @@
#include "effects/GrConvolutionEffect.h"
#include "effects/GrGradientEffects.h"
#include "effects/GrMorphologyEffect.h"
+#include "SkLightingImageFilter.h"
#include "GrProgramStageFactory.h"
#include "GrRandom.h"
@@ -23,6 +24,10 @@ bool random_bool(GrRandom* r) {
return r->nextF() > .5f;
}
+SkPoint3 random_point3(GrRandom* r) {
+ return SkPoint3(r->nextF(), r->nextF(), r->nextF());
+}
+
typedef GrGLProgram::StageDesc StageDesc;
// TODO: Effects should be able to register themselves for inclusion in the
// randomly generated shaders. They should be able to configure themselves
@@ -35,6 +40,12 @@ GrCustomStage* create_random_effect(StageDesc* stageDesc,
kDilate_EffectType,
kRadialGradient_EffectType,
kRadial2Gradient_EffectType,
+ kDiffuseDistant_EffectType,
+ kDiffusePoint_EffectType,
+ kDiffuseSpot_EffectType,
+ kSpecularDistant_EffectType,
+ kSpecularPoint_EffectType,
+ kSpecularSpot_EffectType,
kSweepGradient_EffectType,
kEffectCount
@@ -107,6 +118,86 @@ GrCustomStage* create_random_effect(StageDesc* stageDesc,
case kSweepGradient_EffectType: {
return SkNEW(GrSweepGradient);
}
+ case kDiffuseDistant_EffectType: {
+ SkPoint3 direction = random_point3(random);
+ direction.normalize();
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar kd = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitDiffuse(direction, lightColor, surfaceScale, kd));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
+ case kDiffusePoint_EffectType: {
+ SkPoint3 location = random_point3(random);
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar kd = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitDiffuse(location, lightColor, surfaceScale, kd));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
+ case kDiffuseSpot_EffectType: {
+ SkPoint3 location = random_point3(random);
+ SkPoint3 target = random_point3(random);
+ SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
+ SkScalar specularExponent = SkFloatToScalar(random->nextF());
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar ks = SkFloatToScalar(random->nextF());
+ SkScalar shininess = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
+ location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
+ case kSpecularDistant_EffectType: {
+ SkPoint3 direction = random_point3(random);
+ direction.normalize();
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar ks = SkFloatToScalar(random->nextF());
+ SkScalar shininess = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateDistantLitSpecular(direction, lightColor, surfaceScale, ks, shininess));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
+ case kSpecularPoint_EffectType: {
+ SkPoint3 location = random_point3(random);
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar ks = SkFloatToScalar(random->nextF());
+ SkScalar shininess = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreatePointLitSpecular(location, lightColor, surfaceScale, ks, shininess));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
+ case kSpecularSpot_EffectType: {
+ SkPoint3 location = random_point3(random);
+ SkPoint3 target = random_point3(random);
+ SkScalar cutoffAngle = SkFloatToScalar(random->nextF());
+ SkScalar specularExponent = SkFloatToScalar(random->nextF());
+ SkColor lightColor = random->nextU();
+ SkScalar surfaceScale = SkFloatToScalar(random->nextF());
+ SkScalar ks = SkFloatToScalar(random->nextF());
+ SkScalar shininess = SkFloatToScalar(random->nextF());
+ SkAutoTUnref<SkImageFilter> filter(SkLightingImageFilter::CreateSpotLitSpecular(
+ location, target, specularExponent, cutoffAngle, lightColor, surfaceScale, ks, shininess));
+ // does not work with perspective or mul-by-alpha-mask
+ GrCustomStage* stage;
+ SkASSERT(filter->asNewCustomStage(&stage));
+ return stage;
+ }
default:
GrCrash("Unexpected custom effect type");
}