| Index: samplecode/SampleApp.cpp
|
| diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
|
| index 33b38c0876e715b5ddd813323918239c2d23ad5e..1805ca7e5a6d0f97b9488136bc492f3878fd5c96 100644
|
| --- a/samplecode/SampleApp.cpp
|
| +++ b/samplecode/SampleApp.cpp
|
| @@ -49,26 +49,23 @@
|
| class GrContext;
|
| #endif
|
|
|
| +enum OutputColorSpace {
|
| + kLegacy_OutputColorSpace,
|
| + kSRGB_OutputColorSpace,
|
| + kMonitor_OutputColorSpace,
|
| +};
|
| +
|
| const struct {
|
| SkColorType fColorType;
|
| - bool fSRGB;
|
| + OutputColorSpace fColorSpace;
|
| const char* fName;
|
| } gConfig[] = {
|
| - { kN32_SkColorType, false, "L32" },
|
| - { kN32_SkColorType, true, "S32" },
|
| - { kRGBA_F16_SkColorType, true, "F16" },
|
| + { kN32_SkColorType, kLegacy_OutputColorSpace, "L32" },
|
| + { kN32_SkColorType, kSRGB_OutputColorSpace, "S32" },
|
| + { kRGBA_F16_SkColorType, kSRGB_OutputColorSpace, "F16" },
|
| + { kRGBA_F16_SkColorType, kMonitor_OutputColorSpace, "F16 Device" },
|
| };
|
|
|
| -static const char* find_config_name(const SkImageInfo& info) {
|
| - for (const auto& config : gConfig) {
|
| - if (config.fColorType == info.colorType() &&
|
| - config.fSRGB == (info.colorSpace() != nullptr)) {
|
| - return config.fName;
|
| - }
|
| - }
|
| - return "???";
|
| -}
|
| -
|
| // Should be 3x + 1
|
| #define kMaxFatBitsScale 28
|
|
|
| @@ -322,8 +319,20 @@ public:
|
| kRGBA_F16_SkColorType == win->info().colorType() ||
|
| fActualColorBits > 24) {
|
| // We made/have an off-screen surface. Get the contents as an SkImage:
|
| + SkImageInfo offscreenInfo = win->info();
|
| + if (kMonitor_OutputColorSpace == gConfig[win->getColorConfigIndex()].fColorSpace) {
|
| + // This is a big hack. We want our final output to be color "correct". If we snap
|
| + // an image in the gamut of the monitor, and then render to FBO0 (which we've tagged
|
| + // as sRGB), then we end up doing round-trip gamut conversion, and still seeing the
|
| + // same colors on-screen as if we weren't color managed at all.
|
| + // Instead, we readPixels into a buffer that we claim is sRGB (readPixels doesn't
|
| + // do gamut conversion), so these pixels then get thrown directly at the monitor,
|
| + // giving us the expected results (the output is adapted to the monitor's gamut).
|
| + auto srgb = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
|
| + offscreenInfo = offscreenInfo.makeColorSpace(srgb);
|
| + }
|
| SkBitmap bm;
|
| - bm.allocPixels(win->info());
|
| + bm.allocPixels(offscreenInfo);
|
| renderingCanvas->readPixels(&bm, 0, 0);
|
| SkPixmap pm;
|
| bm.peekPixels(&pm);
|
| @@ -815,6 +824,7 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
|
|
|
| fMSAASampleCount = FLAGS_msaa;
|
| fDeepColor = FLAGS_deepColor;
|
| + fColorConfigIndex = 0;
|
|
|
| if (FLAGS_list) {
|
| listTitles();
|
| @@ -892,7 +902,11 @@ SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* dev
|
| int itemID;
|
|
|
| itemID = fAppMenu->appendList("ColorType", "ColorType", sinkID, 0,
|
| - gConfig[0].fName, gConfig[1].fName, gConfig[2].fName, nullptr);
|
| + gConfig[0].fName,
|
| + gConfig[1].fName,
|
| + gConfig[2].fName,
|
| + gConfig[3].fName,
|
| + nullptr);
|
| fAppMenu->assignKeyEquivalentToItem(itemID, 'C');
|
|
|
| itemID = fAppMenu->appendList("Device Type", "Device Type", sinkID, 0,
|
| @@ -1566,6 +1580,50 @@ void SampleWindow::postAnimatingEvent() {
|
| }
|
| }
|
|
|
| +static sk_sp<SkColorSpace> getMonitorColorSpace() {
|
| +#if defined(SK_BUILD_FOR_MAC)
|
| + CGColorSpaceRef cs = CGDisplayCopyColorSpace(CGMainDisplayID());
|
| + CFDataRef dataRef = CGColorSpaceCopyICCProfile(cs);
|
| + const uint8_t* data = CFDataGetBytePtr(dataRef);
|
| + size_t size = CFDataGetLength(dataRef);
|
| +
|
| + sk_sp<SkColorSpace> colorSpace = SkColorSpace::NewICC(data, size);
|
| +
|
| + CFRelease(cs);
|
| + CFRelease(dataRef);
|
| + return colorSpace;
|
| +#elif defined(SK_BUILD_FOR_WIN)
|
| + DISPLAY_DEVICE dd = { sizeof(DISPLAY_DEVICE) };
|
| +
|
| + // Chrome's code for this currently just gets the primary monitor's profile. This code iterates
|
| + // over all attached monitors, so it's "better" in that sense. Making intelligent use of this
|
| + // information (via things like MonitorFromWindow or MonitorFromRect to pick the correct
|
| + // profile for a particular window or region of a window), is an exercise left to the reader.
|
| + for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
|
| + if (dd.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
|
| + // There are other helpful things in dd at this point:
|
| + // dd.DeviceString has a longer name for the adapter
|
| + // dd.StateFlags indicates primary display, mirroring, etc...
|
| + HDC dc = CreateDC(NULL, dd.DeviceName, NULL, NULL);
|
| + if (dc) {
|
| + char icmPath[MAX_PATH + 1];
|
| + DWORD pathLength = MAX_PATH;
|
| + BOOL success = GetICMProfile(dc, &pathLength, icmPath);
|
| + DeleteDC(dc);
|
| + if (success) {
|
| + sk_sp<SkData> iccData = SkData::MakeFromFileName(icmPath);
|
| + return SkColorSpace::NewICC(iccData->data(), iccData->size());
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return nullptr;
|
| +#else
|
| + return nullptr;
|
| +#endif
|
| +}
|
| +
|
| bool SampleWindow::onEvent(const SkEvent& evt) {
|
| if (evt.isType(gUpdateWindowTitleEvtName)) {
|
| this->updateTitle();
|
| @@ -1592,12 +1650,29 @@ bool SampleWindow::onEvent(const SkEvent& evt) {
|
| return true;
|
| }
|
| if (SkOSMenu::FindListIndex(evt, "ColorType", &selected)) {
|
| - auto colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
|
| + fColorConfigIndex = selected;
|
| + sk_sp<SkColorSpace> colorSpace = nullptr;
|
| + switch (gConfig[selected].fColorSpace) {
|
| + case kSRGB_OutputColorSpace:
|
| + colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
|
| + break;
|
| + case kMonitor_OutputColorSpace:
|
| + colorSpace = getMonitorColorSpace();
|
| + if (!colorSpace) {
|
| + // Fallback for platforms / machines where we can't get a monitor profile
|
| + colorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
|
| + }
|
| + break;
|
| + case kLegacy_OutputColorSpace:
|
| + default:
|
| + // Do nothing
|
| + break;
|
| + }
|
| if (kRGBA_F16_SkColorType == gConfig[selected].fColorType) {
|
| + SkASSERT(colorSpace);
|
| colorSpace = colorSpace->makeLinearGamma();
|
| }
|
| - this->setDeviceColorType(gConfig[selected].fColorType,
|
| - gConfig[selected].fSRGB ? colorSpace : nullptr);
|
| + this->setDeviceColorType(gConfig[selected].fColorType, colorSpace);
|
| return true;
|
| }
|
| if (SkOSMenu::FindSwitchState(evt, "Slide Show", nullptr)) {
|
| @@ -2121,7 +2196,7 @@ void SampleWindow::updateTitle() {
|
| }
|
| #endif
|
|
|
| - title.appendf(" %s", find_config_name(this->info()));
|
| + title.appendf(" %s", gConfig[fColorConfigIndex].fName);
|
|
|
| if (fDevManager && fDevManager->getColorBits() > 24) {
|
| title.appendf(" %d bpc", fDevManager->getColorBits());
|
|
|