aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--example/HelloWorld.cpp2
-rw-r--r--experimental/SkV8Example/SkV8Example.cpp2
-rw-r--r--experimental/iOSSampleApp/SkSampleUIView.mm12
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrContext.h10
-rw-r--r--include/gpu/GrSurface.h2
-rw-r--r--include/views/SkOSWindow_Android.h3
-rw-r--r--include/views/SkOSWindow_Mac.h3
-rw-r--r--include/views/SkOSWindow_SDL.h2
-rw-r--r--include/views/SkOSWindow_Unix.h2
-rw-r--r--include/views/SkOSWindow_Win.h4
-rw-r--r--include/views/SkOSWindow_iOS.h3
-rw-r--r--include/views/SkWindow.h6
-rw-r--r--platform_tools/android/apps/sample_app/src/main/jni/com_skia_SkiaSampleRenderer.cpp3
-rw-r--r--platform_tools/android/apps/visualbench/src/main/jni/SkOSWindow_AndroidNative.cpp1
-rw-r--r--samplecode/SampleApp.cpp90
-rw-r--r--samplecode/SampleApp.h7
-rw-r--r--src/gpu/GrContext.cpp39
-rw-r--r--src/gpu/GrProcessor.cpp2
-rw-r--r--src/gpu/effects/GrGammaEffect.cpp136
-rw-r--r--src/gpu/effects/GrGammaEffect.h42
-rw-r--r--src/utils/win/SkWGL.h5
-rw-r--r--src/utils/win/SkWGL_win.cpp57
-rw-r--r--src/views/SkWindow.cpp11
-rwxr-xr-xsrc/views/ios/SkOSWindow_iOS.mm1
-rw-r--r--src/views/mac/SkOSWindow_Mac.mm3
-rw-r--r--src/views/sdl/SkOSWindow_SDL.cpp3
-rw-r--r--src/views/unix/SkOSWindow_Unix.cpp3
-rw-r--r--src/views/win/SkOSWindow_win.cpp13
-rw-r--r--tests/ApplyGammaTest.cpp156
-rw-r--r--tools/VisualBench/VisualBench.cpp2
-rw-r--r--tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp2
-rw-r--r--tools/viewer/android/Window_android.h6
33 files changed, 541 insertions, 94 deletions
diff --git a/example/HelloWorld.cpp b/example/HelloWorld.cpp
index 892dce1c80..c2dd7d89f1 100644
--- a/example/HelloWorld.cpp
+++ b/example/HelloWorld.cpp
@@ -62,7 +62,7 @@ bool HelloWorldWindow::setUpBackend() {
this->setVisibleP(true);
this->setClipToBounds(false);
- bool result = attach(kNativeGL_BackEndType, 0 /*msaa*/, &fAttachmentInfo);
+ bool result = attach(kNativeGL_BackEndType, 0 /*msaa*/, false, &fAttachmentInfo);
if (false == result) {
SkDebugf("Not possible to create backend.\n");
release();
diff --git a/experimental/SkV8Example/SkV8Example.cpp b/experimental/SkV8Example/SkV8Example.cpp
index fe205d740d..bb448bad15 100644
--- a/experimental/SkV8Example/SkV8Example.cpp
+++ b/experimental/SkV8Example/SkV8Example.cpp
@@ -74,7 +74,7 @@ void SkV8ExampleWindow::windowSizeChanged() {
if (FLAGS_gpu) {
SkOSWindow::AttachmentInfo attachmentInfo;
bool result = this->attach(
- SkOSWindow::kNativeGL_BackEndType, 0, &attachmentInfo);
+ SkOSWindow::kNativeGL_BackEndType, 0, false, &attachmentInfo);
if (!result) {
printf("Failed to attach.");
exit(1);
diff --git a/experimental/iOSSampleApp/SkSampleUIView.mm b/experimental/iOSSampleApp/SkSampleUIView.mm
index bd6d533cc8..8bf7c904e1 100644
--- a/experimental/iOSSampleApp/SkSampleUIView.mm
+++ b/experimental/iOSSampleApp/SkSampleUIView.mm
@@ -47,7 +47,7 @@ public:
#endif
}
- void setUpBackend(SampleWindow* win, int msaaSampleCount) override {
+ void setUpBackend(SampleWindow* win, int msaaSampleCount, bool deepColor) override {
SkASSERT(SkOSWindow::kNone_BackEndType == fBackend);
fBackend = SkOSWindow::kNone_BackEndType;
@@ -65,7 +65,7 @@ public:
break;
}
SkOSWindow::AttachmentInfo info;
- bool result = win->attach(fBackend, msaaSampleCount, &info);
+ bool result = win->attach(fBackend, msaaSampleCount, false, &info);
if (!result) {
SkDebugf("Failed to initialize GL");
return;
@@ -145,7 +145,7 @@ public:
if (NULL != fCurContext) {
SkOSWindow::AttachmentInfo info;
- win->attach(fBackend, fMSAASampleCount, &info);
+ win->attach(fBackend, fMSAASampleCount, false, &info);
glBindFramebuffer(GL_FRAMEBUFFER, fLayerFBO);
GrBackendRenderTargetDesc desc;
@@ -177,7 +177,11 @@ public:
return NULL;
#endif
}
-
+
+ int getColorBits() override {
+ return 24;
+ }
+
bool isUsingGL() const { return SkOSWindow::kNone_BackEndType != fBackend; }
private:
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index 5919e24b59..f0bb333e94 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -285,6 +285,8 @@
'<(skia_src_path)/gpu/effects/GrDistanceFieldGeoProc.h',
'<(skia_src_path)/gpu/effects/GrDitherEffect.cpp',
'<(skia_src_path)/gpu/effects/GrDitherEffect.h',
+ '<(skia_src_path)/gpu/effects/GrGammaEffect.cpp',
+ '<(skia_src_path)/gpu/effects/GrGammaEffect.h',
'<(skia_src_path)/gpu/effects/GrMatrixConvolutionEffect.cpp',
'<(skia_src_path)/gpu/effects/GrMatrixConvolutionEffect.h',
'<(skia_src_path)/gpu/effects/GrOvalEffect.cpp',
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 6f5ca981e5..b6fa30bc35 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -293,8 +293,16 @@ public:
uint32_t pixelOpsFlags = 0);
/**
+ * Copies contents of src to dst, while applying a gamma curve. Fails if the two surfaces
+ * are not identically sized.
+ * @param dst the surface to copy to.
+ * @param src the texture to copy from.
+ * @param gamma the gamma value to apply.
+ */
+ bool applyGamma(GrRenderTarget* dst, GrTexture* src, SkScalar gamma);
+
+ /**
* Copies a rectangle of texels from src to dst.
- * bounds.
* @param dst the surface to copy to.
* @param src the surface to copy from.
* @param srcRect the rectangle of the src that should be copied.
diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h
index b87b2dbaf0..8c6930a7a7 100644
--- a/include/gpu/GrSurface.h
+++ b/include/gpu/GrSurface.h
@@ -100,7 +100,7 @@ public:
* packed.
* @param pixelOpsFlags See the GrContext::PixelOpsFlags enum.
*
- * @return true if the read succeeded, false if not. The read can fail because of an
+ * @return true if the write succeeded, false if not. The write can fail because of an
* unsupported pixel config.
*/
bool writePixels(int left, int top, int width, int height,
diff --git a/include/views/SkOSWindow_Android.h b/include/views/SkOSWindow_Android.h
index 74175bafd1..234e65c256 100644
--- a/include/views/SkOSWindow_Android.h
+++ b/include/views/SkOSWindow_Android.h
@@ -28,7 +28,8 @@ public:
kNativeGL_BackEndType,
};
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ AttachmentInfo* info);
void release();
void present();
bool makeFullscreen() { return true; }
diff --git a/include/views/SkOSWindow_Mac.h b/include/views/SkOSWindow_Mac.h
index efa97bf872..4558a58833 100644
--- a/include/views/SkOSWindow_Mac.h
+++ b/include/views/SkOSWindow_Mac.h
@@ -33,7 +33,8 @@ public:
};
void release();
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ AttachmentInfo*);
void present();
bool makeFullscreen();
diff --git a/include/views/SkOSWindow_SDL.h b/include/views/SkOSWindow_SDL.h
index 6823441715..1ab51ca415 100644
--- a/include/views/SkOSWindow_SDL.h
+++ b/include/views/SkOSWindow_SDL.h
@@ -29,7 +29,7 @@ public:
};
void release();
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*);
void present();
bool makeFullscreen();
void setVsync(bool);
diff --git a/include/views/SkOSWindow_Unix.h b/include/views/SkOSWindow_Unix.h
index 30386da183..2e1b9ccc81 100644
--- a/include/views/SkOSWindow_Unix.h
+++ b/include/views/SkOSWindow_Unix.h
@@ -44,7 +44,7 @@ public:
#endif // SK_COMMAND_BUFFER
};
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*);
void release();
void present();
diff --git a/include/views/SkOSWindow_Win.h b/include/views/SkOSWindow_Win.h
index eb8b1fc892..8d5378108e 100644
--- a/include/views/SkOSWindow_Win.h
+++ b/include/views/SkOSWindow_Win.h
@@ -47,7 +47,7 @@ public:
#endif // SK_SUPPORT_GPU
};
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor, AttachmentInfo*);
void release();
void present();
@@ -127,7 +127,7 @@ private:
void updateSize();
#if SK_SUPPORT_GPU
- bool attachGL(int msaaSampleCount, AttachmentInfo* info);
+ bool attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info);
void detachGL();
void presentGL();
diff --git a/include/views/SkOSWindow_iOS.h b/include/views/SkOSWindow_iOS.h
index 5a8b2e3d2f..c0b2fc3f0a 100644
--- a/include/views/SkOSWindow_iOS.h
+++ b/include/views/SkOSWindow_iOS.h
@@ -22,7 +22,8 @@ public:
};
void release();
- bool attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo*);
+ bool attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ AttachmentInfo*);
void present();
bool makeFullscreen() { return true; }
diff --git a/include/views/SkWindow.h b/include/views/SkWindow.h
index b4fabd253e..341046aacc 100644
--- a/include/views/SkWindow.h
+++ b/include/views/SkWindow.h
@@ -32,8 +32,14 @@ public:
virtual ~SkWindow();
struct AttachmentInfo {
+ AttachmentInfo()
+ : fSampleCount(0)
+ , fStencilBits(0)
+ , fColorBits(0) {}
+
int fSampleCount;
int fStencilBits;
+ int fColorBits;
};
SkSurfaceProps getSurfaceProps() const { return fSurfaceProps; }
diff --git a/platform_tools/android/apps/sample_app/src/main/jni/com_skia_SkiaSampleRenderer.cpp b/platform_tools/android/apps/sample_app/src/main/jni/com_skia_SkiaSampleRenderer.cpp
index e5c6660921..f233a2fc39 100644
--- a/platform_tools/android/apps/sample_app/src/main/jni/com_skia_SkiaSampleRenderer.cpp
+++ b/platform_tools/android/apps/sample_app/src/main/jni/com_skia_SkiaSampleRenderer.cpp
@@ -61,7 +61,8 @@ SkOSWindow::SkOSWindow(void*) : fDestroyRequested(false) {
SkOSWindow::~SkOSWindow() {
}
-bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int /*msaaSampleCount*/, AttachmentInfo* info)
+bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int /*msaaSampleCount*/,
+ bool /*deepColor*/, AttachmentInfo* info)
{
JNIEnv* env = gActivityGlue.m_env;
if (!env || !gWindowGlue.m_getMSAASampleCount || !gWindowGlue.m_obj) {
diff --git a/platform_tools/android/apps/visualbench/src/main/jni/SkOSWindow_AndroidNative.cpp b/platform_tools/android/apps/visualbench/src/main/jni/SkOSWindow_AndroidNative.cpp
index 644191d3d7..2c53eb0812 100644
--- a/platform_tools/android/apps/visualbench/src/main/jni/SkOSWindow_AndroidNative.cpp
+++ b/platform_tools/android/apps/visualbench/src/main/jni/SkOSWindow_AndroidNative.cpp
@@ -23,6 +23,7 @@ SkOSWindow::~SkOSWindow() {
bool SkOSWindow::attach(SkBackEndTypes attachType,
int /*msaaSampleCount*/,
+ bool /*deepColor*/
AttachmentInfo* info) {
static const EGLint kEGLContextAttribsForOpenGL[] = {
EGL_NONE
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 6500612a52..1df96c80c8 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -16,6 +16,7 @@
#include "SkData.h"
#include "SkDocument.h"
#include "SkGraphics.h"
+#include "SkImage_Base.h"
#include "SkImageEncoder.h"
#include "SkOSFile.h"
#include "SkPaint.h"
@@ -178,6 +179,8 @@ public:
fCurIntf = nullptr;
fCurRenderTarget = nullptr;
fMSAASampleCount = 0;
+ fDeepColor = false;
+ fActualColorBits = 0;
#endif
fBackend = kNone_BackEndType;
}
@@ -190,7 +193,7 @@ public:
#endif
}
- void setUpBackend(SampleWindow* win, int msaaSampleCount) override {
+ void setUpBackend(SampleWindow* win, int msaaSampleCount, bool deepColor) override {
SkASSERT(kNone_BackEndType == fBackend);
fBackend = kNone_BackEndType;
@@ -219,12 +222,15 @@ public:
break;
}
AttachmentInfo attachmentInfo;
- bool result = win->attach(fBackend, msaaSampleCount, &attachmentInfo);
+ bool result = win->attach(fBackend, msaaSampleCount, deepColor, &attachmentInfo);
if (!result) {
SkDebugf("Failed to initialize GL");
return;
}
fMSAASampleCount = msaaSampleCount;
+ fDeepColor = deepColor;
+ // Assume that we have at least 24-bit output, for backends that don't supply this data
+ fActualColorBits = SkTMax(attachmentInfo.fColorBits, 24);
SkASSERT(nullptr == fCurIntf);
SkAutoTUnref<const GrGLInterface> glInterface;
@@ -294,9 +300,12 @@ public:
#if SK_SUPPORT_GPU
if (IsGpuDeviceType(dType) && fCurContext) {
SkSurfaceProps props(win->getSurfaceProps());
- if (kRGBA_F16_SkColorType == win->info().colorType()) {
- // Need to make an off-screen F16 surface - the current render target is
- // (probably) the wrong format.
+ if (kRGBA_F16_SkColorType == win->info().colorType() || fActualColorBits > 24) {
+ // If we're rendering to F16, we need an off-screen surface - the current render
+ // target is most likely the wrong format.
+ //
+ // If we're using a deep (10-bit or higher) surface, we probably need an off-screen
+ // surface. 10-bit, in particular, has strange gamma behavior.
return SkSurface::MakeRenderTarget(fCurContext, SkBudgeted::kNo, win->info(),
fMSAASampleCount, &props).release();
} else {
@@ -313,29 +322,27 @@ public:
if (fCurContext) {
// in case we have queued drawing calls
fCurContext->flush();
+ }
- if (!IsGpuDeviceType(dType)) {
- // need to send the raster bits to the (gpu) window
- const SkBitmap& bm = win->getBitmap();
- fCurRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
- SkImageInfo2GrPixelConfig(bm.colorType(),
- bm.alphaType(),
- bm.profileType(),
- *fCurContext->caps()),
- bm.getPixels(),
- bm.rowBytes(),
- GrContext::kFlushWrites_PixelOp);
- } else if (kRGBA_F16_SkColorType == win->info().colorType()) {
- SkBitmap bm;
- bm.allocPixels(win->info());
- canvas->readPixels(&bm, 0, 0);
- fCurRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
- SkImageInfo2GrPixelConfig(bm.info(),
- *fCurContext->caps()),
- bm.getPixels(),
- bm.rowBytes(),
- GrContext::kFlushWrites_PixelOp);
- }
+ if (!IsGpuDeviceType(dType) ||
+ kRGBA_F16_SkColorType == win->info().colorType() ||
+ fActualColorBits > 24) {
+ // We made/have an off-screen surface. Get the contents as an SkImage:
+ SkBitmap bm;
+ bm.allocPixels(win->info());
+ canvas->readPixels(&bm, 0, 0);
+ SkPixmap pm;
+ bm.peekPixels(&pm);
+ sk_sp<SkImage> image(SkImage::MakeTextureFromPixmap(fCurContext, pm,
+ SkBudgeted::kNo));
+ GrTexture* texture = as_IB(image)->peekTexture();
+ SkASSERT(texture);
+
+ // With ten-bit output, we need to manually apply the gamma of the output device
+ // (unless we're in non-gamma correct mode, in which case our data is already
+ // fake-sRGB, like we're expected to put in the 10-bit buffer):
+ bool doGamma = (fActualColorBits == 30) && SkImageInfoIsGammaCorrect(win->info());
+ fCurContext->applyGamma(fCurRenderTarget, texture, doGamma ? 1.0f / 2.2f : 1.0f);
}
#endif
@@ -346,8 +353,9 @@ public:
#if SK_SUPPORT_GPU
if (fCurContext) {
AttachmentInfo attachmentInfo;
- win->attach(fBackend, fMSAASampleCount, &attachmentInfo);
+ win->attach(fBackend, fMSAASampleCount, fDeepColor, &attachmentInfo);
SkSafeUnref(fCurRenderTarget);
+ fActualColorBits = SkTMax(attachmentInfo.fColorBits, 24);
fCurRenderTarget = win->renderTarget(attachmentInfo, fCurIntf, fCurContext);
}
#endif
@@ -369,6 +377,14 @@ public:
#endif
}
+ int getColorBits() override {
+#if SK_SUPPORT_GPU
+ return fActualColorBits;
+#else
+ return 24;
+#endif
+ }
+
private:
#if SK_SUPPORT_GPU
@@ -376,6 +392,8 @@ private:
const GrGLInterface* fCurIntf;
GrRenderTarget* fCurRenderTarget;
int fMSAASampleCount;
+ bool fDeepColor;
+ int fActualColorBits;
#endif
SkOSWindow::SkBackEndTypes fBackend;
@@ -773,6 +791,7 @@ static void restrict_samples(SkTDArray<const SkViewFactory*>& factories, const S
DEFINE_string(slide, "", "Start on this sample.");
DEFINE_int32(msaa, 0, "Request multisampling with this count.");
+DEFINE_bool(deepColor, false, "Request deep color (10-bit/channel or more) display buffer.");
DEFINE_string(pictureDir, "", "Read pictures from here.");
DEFINE_string(picture, "", "Path to single picture.");
DEFINE_string(sequence, "", "Path to file containing the desired samples/gms to show.");
@@ -861,6 +880,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
}
fMSAASampleCount = FLAGS_msaa;
+ fDeepColor = FLAGS_deepColor;
if (FLAGS_list) {
listTitles();
@@ -1023,7 +1043,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
devManager->ref();
fDevManager = devManager;
}
- fDevManager->setUpBackend(this, fMSAASampleCount);
+ fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
// If another constructor set our dimensions, ensure that our
// onSizeChange gets called.
@@ -1847,7 +1867,7 @@ void SampleWindow::setDeviceType(DeviceType type) {
fDevManager->tearDownBackend(this);
fDeviceType = type;
- fDevManager->setUpBackend(this, fMSAASampleCount);
+ fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
this->updateTitle();
this->inval(nullptr);
@@ -1857,7 +1877,7 @@ void SampleWindow::setDeviceColorType(SkColorType ct, SkColorProfileType pt) {
this->setColorType(ct, pt);
fDevManager->tearDownBackend(this);
- fDevManager->setUpBackend(this, fMSAASampleCount);
+ fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
this->updateTitle();
this->inval(nullptr);
@@ -1884,7 +1904,7 @@ void SampleWindow::toggleFPS() {
void SampleWindow::toggleDistanceFieldFonts() {
// reset backend
fDevManager->tearDownBackend(this);
- fDevManager->setUpBackend(this, fMSAASampleCount);
+ fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
SkSurfaceProps props = this->getSurfaceProps();
uint32_t flags = props.flags() ^ SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
@@ -1897,7 +1917,7 @@ void SampleWindow::toggleDistanceFieldFonts() {
void SampleWindow::setPixelGeometry(int pixelGeometryIndex) {
// reset backend
fDevManager->tearDownBackend(this);
- fDevManager->setUpBackend(this, fMSAASampleCount);
+ fDevManager->setUpBackend(this, fMSAASampleCount, fDeepColor);
const SkSurfaceProps& oldProps = this->getSurfaceProps();
SkSurfaceProps newProps(oldProps.flags(), SkSurfaceProps::kLegacyFontHost_InitType);
@@ -2162,6 +2182,10 @@ void SampleWindow::updateTitle() {
title.appendf(" %s", find_config_name(this->info()));
+ if (fDevManager && fDevManager->getColorBits() > 24) {
+ title.appendf(" %d bpc", fDevManager->getColorBits());
+ }
+
if (gTreatSkColorAsSRGB) {
title.append(" sRGB");
}
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
index 18e75640d7..ad7a871b98 100644
--- a/samplecode/SampleApp.h
+++ b/samplecode/SampleApp.h
@@ -74,7 +74,7 @@ public:
public:
- virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) = 0;
+ virtual void setUpBackend(SampleWindow* win, int msaaSampleCount, bool deepColor) = 0;
virtual void tearDownBackend(SampleWindow* win) = 0;
@@ -97,6 +97,10 @@ public:
// return the GrRenderTarget backing gpu devices (nullptr if not built with GPU support)
virtual GrRenderTarget* getGrRenderTarget() = 0;
+
+ // return the color depth of the output device
+ virtual int getColorBits() = 0;
+
private:
typedef SkRefCnt INHERITED;
};
@@ -212,6 +216,7 @@ private:
unsigned fFlipAxis;
int fMSAASampleCount;
+ bool fDeepColor;
SkScalar fZoomCenterX, fZoomCenterY;
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 31845f9d6d..3ea67c9f01 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -20,6 +20,7 @@
#include "batches/GrCopySurfaceBatch.h"
#include "effects/GrConfigConversionEffect.h"
+#include "effects/GrGammaEffect.h"
#include "text/GrTextBlobCache.h"
#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
@@ -529,6 +530,44 @@ bool GrContext::readSurfacePixels(GrSurface* src,
return true;
}
+bool GrContext::applyGamma(GrRenderTarget* dst, GrTexture* src, SkScalar gamma){
+ ASSERT_SINGLE_OWNER
+ RETURN_FALSE_IF_ABANDONED
+ ASSERT_OWNED_RESOURCE(dst);
+ ASSERT_OWNED_RESOURCE(src);
+ GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::applyGamma");
+
+ // Dimensions must match exactly.
+ if (dst->width() != src->width() || dst->height() != src->height()) {
+ return false;
+ }
+
+ SkSurfaceProps props(SkSurfaceProps::kGammaCorrect_Flag,
+ SkSurfaceProps::kLegacyFontHost_InitType);
+ sk_sp<GrDrawContext> drawContext(this->drawContext(sk_ref_sp(dst), &props));
+ if (!drawContext) {
+ return false;
+ }
+
+ GrPaint paint;
+ if (SkScalarNearlyEqual(gamma, 1.0f)) {
+ paint.addColorTextureProcessor(src, GrCoordTransform::MakeDivByTextureWHMatrix(src));
+ } else {
+ SkAutoTUnref<const GrFragmentProcessor> fp;
+ fp.reset(GrGammaEffect::Create(src, gamma));
+ paint.addColorFragmentProcessor(fp);
+ }
+ paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
+ paint.setGammaCorrect(true);
+
+ SkRect rect;
+ src->getBoundsRect(&rect);
+ drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect);
+
+ this->flushSurfaceWrites(dst);
+ return true;
+}
+
void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) {
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 0d3f8d9166..29482ccc63 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -48,7 +48,7 @@ GrProcessorTestFactory<GrGeometryProcessor>::GetFactories() {
* we verify the count is as expected. If a new factory is added, then these numbers must be
* manually adjusted.
*/
-static const int kFPFactoryCount = 39;
+static const int kFPFactoryCount = 40;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 6;
diff --git a/src/gpu/effects/GrGammaEffect.cpp b/src/gpu/effects/GrGammaEffect.cpp
new file mode 100644
index 0000000000..b2aa48aad2
--- /dev/null
+++ b/src/gpu/effects/GrGammaEffect.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrGammaEffect.h"
+
+#include "GrContext.h"
+#include "GrCoordTransform.h"
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "GrProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+class GrGLGammaEffect : public GrGLSLFragmentProcessor {
+public:
+ void emitCode(EmitArgs& args) override {
+ const GrGammaEffect& ge = args.fFp.cast<GrGammaEffect>();
+ GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+ GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
+
+ const char* gammaUniName = nullptr;
+ if (!ge.gammaIsSRGB()) {
+ fGammaUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kFloat_GrSLType,
+ kDefault_GrSLPrecision, "Gamma", &gammaUniName);
+ }
+
+ GrGLSLShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
+ SkString tmpDecl;
+ tmpVar.appendDecl(args.fGLSLCaps, &tmpDecl);
+
+ SkString srgbFuncName;
+ if (ge.gammaIsSRGB()) {
+ static const GrGLSLShaderVar gSrgbArgs[] = {
+ GrGLSLShaderVar("x", kFloat_GrSLType),
+ };
+
+ fragBuilder->emitFunction(kFloat_GrSLType,
+ "linear_to_srgb",
+ SK_ARRAY_COUNT(gSrgbArgs),
+ gSrgbArgs,
+ "return (x <= 0.0031308) ? (x * 12.92) "
+ ": (1.055 * pow(x, 0.416666667) - 0.055);",
+ &srgbFuncName);
+ }
+
+ fragBuilder->codeAppendf("%s;", tmpDecl.c_str());
+
+ fragBuilder->codeAppendf("%s = ", tmpVar.c_str());
+ fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fCoords[0].c_str(),
+ args.fCoords[0].getType());
+ fragBuilder->codeAppend(";");
+
+ if (ge.gammaIsSRGB()) {
+ fragBuilder->codeAppendf("%s = vec4(%s(%s.r), %s(%s.g), %s(%s.b), %s.a);",
+ args.fOutputColor,
+ srgbFuncName.c_str(), tmpVar.c_str(),
+ srgbFuncName.c_str(), tmpVar.c_str(),
+ srgbFuncName.c_str(), tmpVar.c_str(),
+ tmpVar.c_str());
+ } else {
+ fragBuilder->codeAppendf("%s = vec4(pow(%s.rgb, vec3(%s)), %s.a);",
+ args.fOutputColor, tmpVar.c_str(), gammaUniName,
+ tmpVar.c_str());
+ }
+ }
+
+ void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {
+ const GrGammaEffect& ge = proc.cast<GrGammaEffect>();
+ if (!ge.gammaIsSRGB()) {
+ pdman.set1f(fGammaUni, ge.gamma());
+ }
+ }
+
+ static inline void GenKey(const GrProcessor& processor, const GrGLSLCaps&,
+ GrProcessorKeyBuilder* b) {
+ const GrGammaEffect& ge = processor.cast<GrGammaEffect>();
+ uint32_t key = ge.gammaIsSRGB() ? 0x1 : 0x0;
+ b->add32(key);
+ }
+
+private:
+ GrGLSLProgramDataManager::UniformHandle fGammaUni;
+
+ typedef GrGLSLFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGammaEffect::GrGammaEffect(GrTexture* texture, SkScalar gamma)
+ : INHERITED(texture, GrCoordTransform::MakeDivByTextureWHMatrix(texture)) {
+ this->initClassID<GrGammaEffect>();
+
+ fGamma = gamma;
+ fGammaIsSRGB = SkScalarNearlyEqual(gamma, 1.0f / 2.2f);
+}
+
+bool GrGammaEffect::onIsEqual(const GrFragmentProcessor& s) const {
+ const GrGammaEffect& other = s.cast<GrGammaEffect>();
+ return
+ other.fGammaIsSRGB == fGammaIsSRGB &&
+ other.fGamma == fGamma;
+}
+
+void GrGammaEffect::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrGammaEffect);
+
+const GrFragmentProcessor* GrGammaEffect::TestCreate(GrProcessorTestData* d) {
+ // We want to be sure and test sRGB sometimes
+ bool srgb = d->fRandom->nextBool();
+ return new GrGammaEffect(d->fTextures[GrProcessorUnitTest::kSkiaPMTextureIdx],
+ srgb ? 1.0f / 2.2f : d->fRandom->nextRangeScalar(0.5f, 2.0f));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrGammaEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
+ GrProcessorKeyBuilder* b) const {
+ GrGLGammaEffect::GenKey(*this, caps, b);
+}
+
+GrGLSLFragmentProcessor* GrGammaEffect::onCreateGLSLInstance() const {
+ return new GrGLGammaEffect();
+}
+
+const GrFragmentProcessor* GrGammaEffect::Create(GrTexture* texture, SkScalar gamma) {
+ return new GrGammaEffect(texture, gamma);
+}
diff --git a/src/gpu/effects/GrGammaEffect.h b/src/gpu/effects/GrGammaEffect.h
new file mode 100644
index 0000000000..44d6d6707c
--- /dev/null
+++ b/src/gpu/effects/GrGammaEffect.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGammaEffect_DEFINED
+#define GrGammaEffect_DEFINED
+
+#include "GrSingleTextureEffect.h"
+
+class GrGammaEffect : public GrSingleTextureEffect {
+public:
+ /**
+ * Creates an effect that applies a gamma curve. The source texture is always
+ * sampled unfiltered and with clamping.
+ */
+ static const GrFragmentProcessor* Create(GrTexture*, SkScalar gamma);
+
+ const char* name() const override { return "Gamma"; }
+
+ bool gammaIsSRGB() const { return fGammaIsSRGB; }
+ SkScalar gamma() const { return fGamma; }
+
+private:
+ GrGammaEffect(GrTexture*, SkScalar gamma);
+
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+ void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
+ bool onIsEqual(const GrFragmentProcessor&) const override;
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
+
+ bool fGammaIsSRGB;
+ SkScalar fGamma;
+
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
+
+ typedef GrSingleTextureEffect INHERITED;
+};
+
+#endif
diff --git a/src/utils/win/SkWGL.h b/src/utils/win/SkWGL.h
index 5322d916b5..ebd95e7a83 100644
--- a/src/utils/win/SkWGL.h
+++ b/src/utils/win/SkWGL.h
@@ -37,6 +37,9 @@
#define SK_WGL_SUPPORT_OPENGL 0x2010
#define SK_WGL_DOUBLE_BUFFER 0x2011
#define SK_WGL_COLOR_BITS 0x2014
+#define SK_WGL_RED_BITS 0x2015
+#define SK_WGL_GREEN_BITS 0x2017
+#define SK_WGL_BLUE_BITS 0x2019
#define SK_WGL_ALPHA_BITS 0x201B
#define SK_WGL_STENCIL_BITS 0x2023
#define SK_WGL_FULL_ACCELERATION 0x2027
@@ -138,7 +141,7 @@ enum SkWGLContextRequest {
* (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be
* created then a compatible profile context will be created.
*/
-HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest context);
+HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor, SkWGLContextRequest context);
/**
* Helper class for creating a pbuffer context and deleting all the handles when finished. This
diff --git a/src/utils/win/SkWGL_win.cpp b/src/utils/win/SkWGL_win.cpp
index 65ffaf1ecf..dc1b4caf1a 100644
--- a/src/utils/win/SkWGL_win.cpp
+++ b/src/utils/win/SkWGL_win.cpp
@@ -288,38 +288,41 @@ SkWGLExtensions::SkWGLExtensions()
///////////////////////////////////////////////////////////////////////////////
static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
- bool doubleBuffered, int msaaSampleCount,
+ bool doubleBuffered, int msaaSampleCount, bool deepColor,
int formatsToTry[2]) {
- int iAttrs[] = {
- SK_WGL_DRAW_TO_WINDOW, TRUE,
- SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE),
- SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
- SK_WGL_SUPPORT_OPENGL, TRUE,
- SK_WGL_COLOR_BITS, 24,
- SK_WGL_ALPHA_BITS, 8,
- SK_WGL_STENCIL_BITS, 8,
- 0, 0
+ auto appendAttr = [](SkTDArray<int>& attrs, int attr, int value) {
+ attrs.push(attr);
+ attrs.push(value);
};
+ SkTDArray<int> iAttrs;
+ appendAttr(iAttrs, SK_WGL_DRAW_TO_WINDOW, TRUE);
+ appendAttr(iAttrs, SK_WGL_DOUBLE_BUFFER, (doubleBuffered ? TRUE : FALSE));
+ appendAttr(iAttrs, SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION);
+ appendAttr(iAttrs, SK_WGL_SUPPORT_OPENGL, TRUE);
+ if (deepColor) {
+ appendAttr(iAttrs, SK_WGL_RED_BITS, 10);
+ appendAttr(iAttrs, SK_WGL_GREEN_BITS, 10);
+ appendAttr(iAttrs, SK_WGL_BLUE_BITS, 10);
+ appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 2);
+ } else {
+ appendAttr(iAttrs, SK_WGL_COLOR_BITS, 24);
+ appendAttr(iAttrs, SK_WGL_ALPHA_BITS, 8);
+ }
+ appendAttr(iAttrs, SK_WGL_STENCIL_BITS, 8);
+
float fAttrs[] = {0, 0};
// Get a MSAA format if requested and possible.
if (msaaSampleCount > 0 &&
extensions.hasExtension(dc, "WGL_ARB_multisample")) {
- static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
- int msaaIAttrs[kIAttrsCount + 4];
- memcpy(msaaIAttrs, iAttrs, sizeof(int) * kIAttrsCount);
- SkASSERT(0 == msaaIAttrs[kIAttrsCount - 2] &&
- 0 == msaaIAttrs[kIAttrsCount - 1]);
- msaaIAttrs[kIAttrsCount - 2] = SK_WGL_SAMPLE_BUFFERS;
- msaaIAttrs[kIAttrsCount - 1] = TRUE;
- msaaIAttrs[kIAttrsCount + 0] = SK_WGL_SAMPLES;
- msaaIAttrs[kIAttrsCount + 1] = msaaSampleCount;
- msaaIAttrs[kIAttrsCount + 2] = 0;
- msaaIAttrs[kIAttrsCount + 3] = 0;
+ SkTDArray<int> msaaIAttrs = iAttrs;
+ appendAttr(msaaIAttrs, SK_WGL_SAMPLE_BUFFERS, TRUE);
+ appendAttr(msaaIAttrs, SK_WGL_SAMPLES, msaaSampleCount);
+ appendAttr(msaaIAttrs, 0, 0);
unsigned int num;
int formats[64];
- extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
+ extensions.choosePixelFormat(dc, msaaIAttrs.begin(), fAttrs, 64, formats, &num);
num = SkTMin(num, 64U);
formatsToTry[0] = extensions.selectFormat(formats, num, dc, msaaSampleCount);
}
@@ -327,7 +330,8 @@ static void get_pixel_formats_to_try(HDC dc, const SkWGLExtensions& extensions,
// Get a non-MSAA format
int* format = -1 == formatsToTry[0] ? &formatsToTry[0] : &formatsToTry[1];
unsigned int num;
- extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, format, &num);
+ appendAttr(iAttrs, 0, 0);
+ extensions.choosePixelFormat(dc, iAttrs.begin(), fAttrs, 1, format, &num);
}
static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextRequest contextType) {
@@ -393,7 +397,8 @@ static HGLRC create_gl_context(HDC dc, SkWGLExtensions extensions, SkWGLContextR
return glrc;
}
-HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest contextType) {
+HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool deepColor,
+ SkWGLContextRequest contextType) {
SkWGLExtensions extensions;
if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
return nullptr;
@@ -402,7 +407,7 @@ HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest contex
BOOL set = FALSE;
int pixelFormatsToTry[] = { -1, -1 };
- get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, pixelFormatsToTry);
+ get_pixel_formats_to_try(dc, extensions, true, msaaSampleCount, deepColor, pixelFormatsToTry);
for (int f = 0;
!set && -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry);
++f) {
@@ -429,7 +434,7 @@ SkWGLPbufferContext* SkWGLPbufferContext::Create(HDC parentDC, int msaaSampleCou
for (int dblBuffer = 0; dblBuffer < 2; ++dblBuffer) {
int pixelFormatsToTry[] = { -1, -1 };
get_pixel_formats_to_try(parentDC, extensions, (0 != dblBuffer), msaaSampleCount,
- pixelFormatsToTry);
+ false, pixelFormatsToTry);
for (int f = 0; -1 != pixelFormatsToTry[f] && f < SK_ARRAY_COUNT(pixelFormatsToTry); ++f) {
HPBUFFER pbuf = extensions.createPbuffer(parentDC, pixelFormatsToTry[f], 1, 1, nullptr);
if (0 != pbuf) {
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index 244bc49742..d06d6bb9eb 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -340,9 +340,14 @@ GrRenderTarget* SkWindow::renderTarget(const AttachmentInfo& attachmentInfo,
//
// Also, we may not have real sRGB support (ANGLE, in particular), so check for
// that, and fall back to L32:
- desc.fConfig = grContext->caps()->srgbSupport() && SkImageInfoIsGammaCorrect(info())
- ? kSkiaGamma8888_GrPixelConfig
- : kSkia8888_GrPixelConfig;
+ //
+ // ... and, if we're using a 10-bit/channel FB0, it doesn't do sRGB conversion on write,
+ // so pretend that it's non-sRGB 8888:
+ desc.fConfig =
+ grContext->caps()->srgbSupport() &&
+ SkImageInfoIsGammaCorrect(info()) &&
+ (attachmentInfo.fColorBits != 30)
+ ? kSkiaGamma8888_GrPixelConfig : kSkia8888_GrPixelConfig;
desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
desc.fSampleCnt = attachmentInfo.fSampleCount;
desc.fStencilBits = attachmentInfo.fStencilBits;
diff --git a/src/views/ios/SkOSWindow_iOS.mm b/src/views/ios/SkOSWindow_iOS.mm
index 2a74ed6b2c..aa7d3759bd 100755
--- a/src/views/ios/SkOSWindow_iOS.mm
+++ b/src/views/ios/SkOSWindow_iOS.mm
@@ -59,6 +59,7 @@ void SkOSWindow::onUpdateMenu(SkOSMenu* menu) {
bool SkOSWindow::attach(SkBackEndTypes /* attachType */,
int /* msaaSampleCount */,
+ bool /* deepColor */,
AttachmentInfo* info) {
[(SkUIView*)fHWND getAttachmentInfo:info];
bool success = true;
diff --git a/src/views/mac/SkOSWindow_Mac.mm b/src/views/mac/SkOSWindow_Mac.mm
index ee5372113d..faf1bbafd2 100644
--- a/src/views/mac/SkOSWindow_Mac.mm
+++ b/src/views/mac/SkOSWindow_Mac.mm
@@ -65,7 +65,8 @@ void SkOSWindow::onUpdateMenu(const SkOSMenu* menu) {
[(SkNSView*)fHWND onUpdateMenu:menu];
}
-bool SkOSWindow::attach(SkBackEndTypes attachType, int sampleCount, AttachmentInfo* info) {
+bool SkOSWindow::attach(SkBackEndTypes attachType, int sampleCount, bool /*deepColor*/,
+ AttachmentInfo* info) {
return [(SkNSView*)fHWND attach:attachType withMSAASampleCount:sampleCount andGetInfo:info];
}
diff --git a/src/views/sdl/SkOSWindow_SDL.cpp b/src/views/sdl/SkOSWindow_SDL.cpp
index 76d43498e8..88b8353b6c 100644
--- a/src/views/sdl/SkOSWindow_SDL.cpp
+++ b/src/views/sdl/SkOSWindow_SDL.cpp
@@ -57,7 +57,8 @@ void SkOSWindow::release() {
}
}
-bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) {
+bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ AttachmentInfo* info) {
this->createWindow(msaaSampleCount);
if (!fWindow) {
return false;
diff --git a/src/views/unix/SkOSWindow_Unix.cpp b/src/views/unix/SkOSWindow_Unix.cpp
index 7f9d168cb8..2f195927e0 100644
--- a/src/views/unix/SkOSWindow_Unix.cpp
+++ b/src/views/unix/SkOSWindow_Unix.cpp
@@ -348,7 +348,8 @@ static void glXSwapInterval(Display* dsp, GLXDrawable drawable, int interval) {
/////////////////////////////////////////////////////////////////////////
-bool SkOSWindow::attach(SkBackEndTypes, int msaaSampleCount, AttachmentInfo* info) {
+bool SkOSWindow::attach(SkBackEndTypes, int msaaSampleCount, bool deepColor,
+ AttachmentInfo* info) {
this->initWindow(msaaSampleCount, info);
if (nullptr == fUnixWindow.fDisplay) {
diff --git a/src/views/win/SkOSWindow_win.cpp b/src/views/win/SkOSWindow_win.cpp
index a8d05d96f7..a5aafd05d1 100644
--- a/src/views/win/SkOSWindow_win.cpp
+++ b/src/views/win/SkOSWindow_win.cpp
@@ -339,10 +339,10 @@ void SkEvent::SignalQueueTimer(SkMSec delay)
#if SK_SUPPORT_GPU
-bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) {
+bool SkOSWindow::attachGL(int msaaSampleCount, bool deepColor, AttachmentInfo* info) {
HDC dc = GetDC((HWND)fHWND);
if (NULL == fHGLRC) {
- fHGLRC = SkCreateWGLContext(dc, msaaSampleCount,
+ fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, deepColor,
kGLPreferCompatibilityProfile_SkWGLContextRequest);
if (NULL == fHGLRC) {
return false;
@@ -353,11 +353,13 @@ bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) {
glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
}
if (wglMakeCurrent(dc, (HGLRC)fHGLRC)) {
- // use DescribePixelFormat to get the stencil bit depth.
+ // use DescribePixelFormat to get the stencil and color bit depth.
int pixelFormat = GetPixelFormat(dc);
PIXELFORMATDESCRIPTOR pfd;
DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
info->fStencilBits = pfd.cStencilBits;
+ // pfd.cColorBits includes alpha, so it will be 32 in 8/8/8/8 and 10/10/10/2
+ info->fColorBits = pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits;
// Get sample count if the MSAA WGL extension is present
SkWGLExtensions extensions;
@@ -651,7 +653,8 @@ void SkOSWindow::presentCommandBuffer() {
#endif // SK_SUPPORT_GPU
// return true on success
-bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, AttachmentInfo* info) {
+bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, bool deepColor,
+ AttachmentInfo* info) {
// attach doubles as "windowResize" so we need to allo
// already bound states to pass through again
@@ -665,7 +668,7 @@ bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount, Attachme
break;
#if SK_SUPPORT_GPU
case kNativeGL_BackEndType:
- result = attachGL(msaaSampleCount, info);
+ result = attachGL(msaaSampleCount, deepColor, info);
break;
#if SK_ANGLE
case kANGLE_BackEndType:
diff --git a/tests/ApplyGammaTest.cpp b/tests/ApplyGammaTest.cpp
new file mode 100644
index 0000000000..dd79b879b5
--- /dev/null
+++ b/tests/ApplyGammaTest.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <initializer_list>
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#include "GrTexture.h"
+#include "GrTextureProvider.h"
+
+#include "SkUtils.h"
+
+ // using anonymous namespace because these functions are used as template params.
+namespace {
+/** convert 0..1 linear value to 0..1 srgb */
+float linear_to_srgb(float linear) {
+ if (linear <= 0.0031308) {
+ return linear * 12.92f;
+ } else {
+ return 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
+ }
+}
+}
+
+bool check_gamma(uint32_t src, uint32_t dst, float gamma, float error, uint32_t* expected) {
+ if (SkScalarNearlyEqual(gamma, 1.f)) {
+ *expected = src;
+ return src == dst;
+ } else {
+ bool result = true;
+ uint32_t expectedColor = src & 0xff000000;
+
+ // Alpha should always be exactly preserved.
+ if ((src & 0xff000000) != (dst & 0xff000000)) {
+ result = false;
+ }
+
+ for (int c = 0; c < 3; ++c) {
+ uint8_t srcComponent = (src & (0xff << (c * 8))) >> (c * 8);
+ float lower = SkTMax(0.f, (float)srcComponent - error);
+ float upper = SkTMin(255.f, (float)srcComponent + error);
+ if (SkScalarNearlyEqual(gamma, 1.0f / 2.2f)) {
+ lower = linear_to_srgb(lower / 255.f);
+ upper = linear_to_srgb(upper / 255.f);
+ } else {
+ lower = powf(lower / 255.f, gamma);
+ upper = powf(upper / 255.f, gamma);
+ }
+ SkASSERT(lower >= 0.f && lower <= 255.f);
+ SkASSERT(upper >= 0.f && upper <= 255.f);
+ uint8_t dstComponent = (dst & (0xff << (c * 8))) >> (c * 8);
+ if (dstComponent < SkScalarFloorToInt(lower * 255.f) ||
+ dstComponent > SkScalarCeilToInt(upper * 255.f)) {
+ result = false;
+ }
+ uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 127.5f);
+ expectedColor |= expectedComponent << (c * 8);
+ }
+
+ *expected = expectedColor;
+ return result;
+ }
+}
+
+DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) {
+ GrContext* context = ctxInfo.fGrContext;
+ static const int kW = 10;
+ static const int kH = 10;
+ static const size_t kRowBytes = sizeof(uint32_t) * kW;
+
+ GrSurfaceDesc baseDesc;
+ baseDesc.fConfig = kRGBA_8888_GrPixelConfig;
+ baseDesc.fWidth = kW;
+ baseDesc.fHeight = kH;
+
+ SkAutoTMalloc<uint32_t> srcPixels(kW * kH);
+ for (int i = 0; i < kW * kH; ++i) {
+ srcPixels.get()[i] = i;
+ }
+
+ SkAutoTMalloc<uint32_t> dstPixels(kW * kH);
+ for (int i = 0; i < kW * kH; ++i) {
+ dstPixels.get()[i] = ~i;
+ }
+
+ SkAutoTMalloc<uint32_t> read(kW * kH);
+
+ // We allow more error on GPUs with lower precision shader variables.
+ float error = context->caps()->shaderCaps()->floatPrecisionVaries() ? 1.2f : 0.5f;
+
+ for (auto sOrigin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
+ for (auto dOrigin : { kBottomLeft_GrSurfaceOrigin, kTopLeft_GrSurfaceOrigin }) {
+ for (auto sFlags : { kRenderTarget_GrSurfaceFlag, kNone_GrSurfaceFlags }) {
+ for (auto gamma : { 1.0f, 1.0f / 1.8f, 1.0f / 2.2f }) {
+ GrSurfaceDesc srcDesc = baseDesc;
+ srcDesc.fOrigin = sOrigin;
+ srcDesc.fFlags = sFlags;
+ GrSurfaceDesc dstDesc = baseDesc;
+ dstDesc.fOrigin = dOrigin;
+ dstDesc.fFlags = kRenderTarget_GrSurfaceFlag;
+
+ SkAutoTUnref<GrTexture> src(
+ context->textureProvider()->createTexture(srcDesc, SkBudgeted::kNo,
+ srcPixels.get(),
+ kRowBytes));
+ SkAutoTUnref<GrTexture> dst(
+ context->textureProvider()->createTexture(dstDesc, SkBudgeted::kNo,
+ dstPixels.get(),
+ kRowBytes));
+ if (!src || !dst) {
+ ERRORF(reporter, "Could not create surfaces for copy surface test.");
+ continue;
+ }
+
+ bool result = context->applyGamma(dst->asRenderTarget(), src, gamma);
+
+ // To make the copied src rect correct we would apply any dst clipping
+ // back to the src rect, but we don't use it again so don't bother.
+ if (!result) {
+ ERRORF(reporter, "Unexpected failure from applyGamma.");
+ continue;
+ }
+
+ sk_memset32(read.get(), 0, kW * kH);
+ if (!dst->readPixels(0, 0, kW, kH, baseDesc.fConfig, read.get(), kRowBytes)) {
+ ERRORF(reporter, "Error calling readPixels");
+ continue;
+ }
+
+ bool abort = false;
+ // Validate that pixels were copied/transformed correctly.
+ for (int y = 0; y < kH && !abort; ++y) {
+ for (int x = 0; x < kW && !abort; ++x) {
+ uint32_t r = read.get()[y * kW + x];
+ uint32_t s = srcPixels.get()[y * kW + x];
+ uint32_t expected;
+ if (!check_gamma(s, r, gamma, error, &expected)) {
+ ERRORF(reporter, "Expected dst %d,%d to contain 0x%08x "
+ "from src 0x%08x and gamma %f. Got %08x",
+ x, y, expected, s, gamma, r);
+ abort = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/tools/VisualBench/VisualBench.cpp b/tools/VisualBench/VisualBench.cpp
index 154c84b6f2..7f2e90c43f 100644
--- a/tools/VisualBench/VisualBench.cpp
+++ b/tools/VisualBench/VisualBench.cpp
@@ -106,7 +106,7 @@ void VisualBench::resetContext() {
void VisualBench::setupContext() {
int screenSamples = FLAGS_offscreen ? 0 : FLAGS_msaa;
- if (!this->attach(kNativeGL_BackEndType, screenSamples, &fAttachmentInfo)) {
+ if (!this->attach(kNativeGL_BackEndType, screenSamples, false, &fAttachmentInfo)) {
SkDebugf("Not possible to create backend.\n");
INHERITED::release();
SkFAIL("Could not create backend\n");
diff --git a/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp b/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
index 3d70be82cd..4162b8f42d 100644
--- a/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
+++ b/tools/gpu/gl/win/CreatePlatformGLTestContext_win.cpp
@@ -92,7 +92,7 @@ WinGLTestContext::WinGLTestContext(GrGLStandard forcedGpuAPI)
HGLRC glrc;
if (nullptr == fPbufferContext) {
- if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, contextType))) {
+ if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, false, contextType))) {
SkDebugf("Could not create rendering context.\n");
this->destroyGLContext();
return;
diff --git a/tools/viewer/android/Window_android.h b/tools/viewer/android/Window_android.h
index 6099f8983e..d41f0a54c2 100644
--- a/tools/viewer/android/Window_android.h
+++ b/tools/viewer/android/Window_android.h
@@ -17,12 +17,12 @@ enum {
/**
* Leave plenty of space between this item and the ones defined in the glue layer
*/
- APP_CMD_INVAL_WINDOW = 64,
+ APP_CMD_INVAL_WINDOW = 64,
};
class Window_android : public Window {
public:
- Window_android() : Window() {}
+ Window_android() : Window() {}
~Window_android() override {}
bool init(android_app* app_state);
@@ -31,7 +31,7 @@ public:
void setTitle(const char*) override;
void show() override {}
- bool attach(BackEndType attachType, int msaaSampleCount) override;
+ bool attach(BackEndType attachType, int msaaSampleCount, bool deepColor) override;
void inval() override;
void paintIfNeeded();