Add MSAA option to SampleApp

Review URL: http://codereview.appspot.com/5969049


git-svn-id: http://skia.googlecode.com/svn/trunk@3627 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/experimental/iOSSampleApp/SkSampleUIView.mm b/experimental/iOSSampleApp/SkSampleUIView.mm
index 5ec6146..b1ec537 100644
--- a/experimental/iOSSampleApp/SkSampleUIView.mm
+++ b/experimental/iOSSampleApp/SkSampleUIView.mm
@@ -108,6 +108,10 @@
     bool isUsingGL() { return usingGL; }
     
     virtual GrContext* getGrContext() { return fGrContext; }
+
+    virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
+        return fGrRenderTarget;
+    }
 private:
     bool usingGL;
     GrContext* fGrContext;
diff --git a/include/views/SkOSWindow_Android.h b/include/views/SkOSWindow_Android.h
index 5818a0a..9b72b48 100644
--- a/include/views/SkOSWindow_Android.h
+++ b/include/views/SkOSWindow_Android.h
@@ -24,7 +24,9 @@
         kNativeGL_BackEndType,
     };
 
-    bool attach(SkBackEndTypes /* attachType */) { return true; }
+    bool attach(SkBackEndTypes /* attachType */, int /* msaaSampleCount */) {
+        return true;
+    }
     void detach() {}
     void present() {}
 
diff --git a/include/views/SkOSWindow_Mac.h b/include/views/SkOSWindow_Mac.h
index 01fa29f..e3bcea9 100644
--- a/include/views/SkOSWindow_Mac.h
+++ b/include/views/SkOSWindow_Mac.h
@@ -16,19 +16,18 @@
     SkOSWindow(void* hwnd);
     ~SkOSWindow();
     void*   getHWND() const { return fHWND; }
-    
+
     virtual bool onDispatchClick(int x, int y, Click::State state, 
                                  void* owner);
-
     enum SkBackEndTypes {
         kNone_BackEndType,
         kNativeGL_BackEndType,
     };
 
     void    detach();
-    bool    attach(SkBackEndTypes attachType);
+    bool    attach(SkBackEndTypes attachType, int msaaSampleCount);
     void    present();
-    
+
 protected:
     // overrides from SkEventSink
     virtual bool onEvent(const SkEvent& evt);
diff --git a/include/views/SkOSWindow_Unix.h b/include/views/SkOSWindow_Unix.h
index 384cc7b..d967579 100644
--- a/include/views/SkOSWindow_Unix.h
+++ b/include/views/SkOSWindow_Unix.h
@@ -39,10 +39,12 @@
         kNativeGL_BackEndType,
     };
 
-    bool attach(SkBackEndTypes attachType);
+    bool attach(SkBackEndTypes attachType, int msaaSampleCount);
     void detach();
     void present();
 
+    int getMSAASampleCount() const { return fMSAASampleCount; }
+
     //static bool PostEvent(SkEvent* evt, SkEventSinkID, SkMSec delay);
 
     //static bool WndProc(SkUnixWindow* w,  XEvent &e);
@@ -60,10 +62,15 @@
     void doPaint();
     void mapWindowAndWait();
 
+    void closeWindow();
+    void initWindow(int newMSAASampleCount);
+
     SkUnixWindow fUnixWindow;
 
     // Needed for GL
     XVisualInfo* fVi;
+    // we recreate the underlying xwindow if this changes
+    int fMSAASampleCount;
 
     typedef SkWindow INHERITED;
 };
diff --git a/include/views/SkOSWindow_Win.h b/include/views/SkOSWindow_Win.h
index 9c76d5c..f61c80a 100644
--- a/include/views/SkOSWindow_Win.h
+++ b/include/views/SkOSWindow_Win.h
@@ -35,7 +35,7 @@
 #endif
     };
 
-    bool attach(SkBackEndTypes attachType);
+    bool attach(SkBackEndTypes attachType, int msaaSampleCount);
     void detach();
     void present();
 
@@ -73,12 +73,12 @@
 
     SkBackEndTypes      fAttached;
 
-    bool attachGL();
+    bool attachGL(int msaaSampleCount);
     void detachGL();
     void presentGL();
 
 #if SK_ANGLE
-    bool attachANGLE();
+    bool attachANGLE(int msaaSampleCount);
     void detachANGLE();
     void presentANGLE();
 #endif
diff --git a/include/views/SkOSWindow_iOS.h b/include/views/SkOSWindow_iOS.h
index 34ce421..33f014c 100755
--- a/include/views/SkOSWindow_iOS.h
+++ b/include/views/SkOSWindow_iOS.h
@@ -25,7 +25,7 @@
     };
 
     void    detach();
-    bool    attach(SkBackEndTypes attachType);
+    bool    attach(SkBackEndTypes attachType, int msaaSampleCount);
     void    present();
 
 protected:
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 92c9e6c..1cd9c67 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -139,7 +139,8 @@
         : fCurContext(NULL)
         , fCurIntf(NULL)
         , fCurRenderTarget(NULL)
-        , fBackend(kNone_BackEndType) {
+        , fBackend(kNone_BackEndType)
+        , fMSAASampleCount(0) {
     }
 
     virtual ~DefaultDeviceManager() {
@@ -148,7 +149,7 @@
         SkSafeUnref(fCurRenderTarget);
     }
 
-    virtual void setUpBackend(SampleWindow* win) {
+    virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) {
         SkASSERT(kNone_BackEndType == fBackend);
 
         fBackend = kNone_BackEndType;
@@ -175,11 +176,12 @@
                 break;
         }
 
-        bool result = win->attach(fBackend);
+        bool result = win->attach(fBackend, msaaSampleCount);
         if (!result) {
             SkDebugf("Failed to initialize GL");
             return;
         }
+        fMSAASampleCount = msaaSampleCount;
 
         SkASSERT(NULL == fCurIntf);
         switch (win->getDeviceType()) {
@@ -287,7 +289,7 @@
     virtual void windowSizeChanged(SampleWindow* win) {
 
         if (fCurContext) {
-            win->attach(fBackend);
+            win->attach(fBackend, fMSAASampleCount);
 
             GrPlatformRenderTargetDesc desc;
             desc.fWidth = SkScalarRound(win->width());
@@ -307,12 +309,18 @@
     virtual GrContext* getGrContext() {
         return fCurContext;
     }
+
+    virtual GrRenderTarget* getGrRenderTarget() SK_OVERRIDE {
+        return fCurRenderTarget;
+    }
+
 private:
     GrContext*              fCurContext;
     const GrGLInterface*    fCurIntf;
     GrRenderTarget*         fCurRenderTarget;
 
     SkOSWindow::SkBackEndTypes fBackend;
+    int fMSAASampleCount;
 
     typedef SampleWindow::DeviceManager INHERITED;
 };
@@ -645,9 +653,10 @@
 }
 
 static void usage(const char * argv0) {
-    SkDebugf("%s [--slide sampleName] [-i resourcePath]\n", argv0);
+    SkDebugf("%s [--slide sampleName] [-i resourcePath] [-msaa sampleCount]\n", argv0);
     SkDebugf("    sampleName: sample at which to start.\n");
     SkDebugf("    resourcePath: directory that stores image resources.\n");
+    SkDebugf("    msaa: request multisampling with the given sample count.\n");
 }
 
 SampleWindow::SampleWindow(void* hwnd, int argc, char** argv, DeviceManager* devManager) : INHERITED(hwnd) {
@@ -663,6 +672,7 @@
 
     const char* resourcePath = NULL;
     fCurrIndex = -1;
+    fMSAASampleCount = 0;
 
     const char* const commandName = argv[0];
     char* const* stop = argv + argc;
@@ -680,7 +690,12 @@
                     fprintf(stderr, "Unknown sample \"%s\"\n", *argv);
                 }
             }
-        } 
+        } else if (strcmp(*argv, "--msaa") == 0) {
+            ++argv;
+            if (argv < stop && **argv) {
+                fMSAASampleCount = atoi(*argv);
+            }
+        }
         else {
             usage(commandName);
         }
@@ -820,7 +835,7 @@
         devManager->ref();
         fDevManager = devManager;
     }
-    fDevManager->setUpBackend(this);
+    fDevManager->setUpBackend(this, fMSAASampleCount);
 
     // If another constructor set our dimensions, ensure that our
     // onSizeChange gets called.
@@ -1671,7 +1686,7 @@
 
     fDeviceType = type;
 
-    fDevManager->setUpBackend(this);
+    fDevManager->setUpBackend(this, fMSAASampleCount);
 
     this->updateTitle();
     this->inval(NULL);
@@ -1867,6 +1882,16 @@
     "null-gl: "
 };
 
+static const bool gDeviceTypeIsGPU[] = {
+    false,
+    false,
+    true,
+#if SK_ANGLE
+    true,
+#endif
+    true
+};
+
 static const char* trystate_str(SkOSMenu::TriState state,
                                 const char trueStr[], const char falseStr[]) {
     if (SkOSMenu::kOnState == state) {
@@ -1926,6 +1951,12 @@
         title.prepend("! ");
     }
 
+    if (gDeviceTypeIsGPU[fDeviceType] &&
+        fDevManager->getGrRenderTarget()->numSamples() > 0) {
+        title.appendf(" [MSAA: %d]",
+                       fDevManager->getGrRenderTarget()->numSamples());
+    }
+
     this->setTitle(title.c_str());
 }
 
diff --git a/samplecode/SampleApp.h b/samplecode/SampleApp.h
index ba404da..0a7b3cf 100644
--- a/samplecode/SampleApp.h
+++ b/samplecode/SampleApp.h
@@ -50,7 +50,7 @@
      */
     class DeviceManager : public SkRefCnt {
     public:
-        virtual void setUpBackend(SampleWindow* win) = 0;
+        virtual void setUpBackend(SampleWindow* win, int msaaSampleCount) = 0;
 
         virtual void tearDownBackend(SampleWindow* win) = 0;
 
@@ -72,6 +72,9 @@
 
         // return the GrContext backing gpu devices
         virtual GrContext* getGrContext() = 0;
+
+        // return the GrRenderTarget backing gpu devices
+        virtual GrRenderTarget* getGrRenderTarget() = 0;
     };
 
     SampleWindow(void* hwnd, int argc, char** argv, DeviceManager*);
@@ -170,6 +173,8 @@
     SkOSMenu::TriState fHintingState;
     unsigned   fFlipAxis;
 
+    int fMSAASampleCount;
+
     int fScrollTestX, fScrollTestY;
     SkScalar fZoomCenterX, fZoomCenterY;
 
diff --git a/src/views/ios/SkOSWindow_iOS.mm b/src/views/ios/SkOSWindow_iOS.mm
index 81ae37c..8813625 100755
--- a/src/views/ios/SkOSWindow_iOS.mm
+++ b/src/views/ios/SkOSWindow_iOS.mm
@@ -54,7 +54,8 @@
     [(SkUIView*)fHWND onUpdateMenu:menu];
 }
 
-bool SkOSWindow::attach(SkBackEndTypes /* attachType */) {
+bool SkOSWindow::attach(SkBackEndTypes /* attachType */,
+                        int /* msaaSampleCount */) {
     bool success = true;
     return success;
 }
diff --git a/src/views/mac/SkNSView.h b/src/views/mac/SkNSView.h
index 60727eb..bf6e67c 100644
--- a/src/views/mac/SkNSView.h
+++ b/src/views/mac/SkNSView.h
@@ -42,7 +42,7 @@
 - (void)postInvalWithRect:(const SkIRect*)rectOrNil;
 - (BOOL)onHandleEvent:(const SkEvent&)event;
 
-- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType;
+- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType withMSAASampleCount:(int) sampleCount;
 - (void)detach;
 - (void)present;
 @end
diff --git a/src/views/mac/SkNSView.mm b/src/views/mac/SkNSView.mm
index 30488ab..1e7be69 100644
--- a/src/views/mac/SkNSView.mm
+++ b/src/views/mac/SkNSView.mm
@@ -226,25 +226,36 @@
 #include <OpenGL/OpenGL.h>
 
 namespace { 
-CGLContextObj createGLContext() {
+CGLContextObj createGLContext(int msaaSampleCount) {
     GLint major, minor;
     CGLGetVersion(&major, &minor);
     
-    const CGLPixelFormatAttribute attributes[] = {
-        kCGLPFAStencilSize, (CGLPixelFormatAttribute)8,
-#if USE_MSAA
-        kCGLPFASampleBuffers, 1,
-        kCGLPFAMultisample,
-        kCGLPFASamples, 8,
-#endif
+    static const CGLPixelFormatAttribute attributes[] = {
+        kCGLPFAStencilSize, (CGLPixelFormatAttribute) 8,
         kCGLPFAAccelerated,
         kCGLPFADoubleBuffer,
         (CGLPixelFormatAttribute)0
     };
     
     CGLPixelFormatObj format;
-    GLint npix;
-    CGLChoosePixelFormat(attributes, &format, &npix);
+    GLint npix = 0;
+    if (msaaSampleCount > 0) {
+        static int kAttributeCount = SK_ARRAY_COUNT(attributes);
+        CGLPixelFormatAttribute msaaAttributes[kAttributeCount + 5];
+        memcpy(msaaAttributes, attributes, sizeof(attributes));
+        SkASSERT(0 == msaaAttributes[kAttributeCount - 1]);
+        msaaAttributes[kAttributeCount - 1] = kCGLPFASampleBuffers;
+        msaaAttributes[kAttributeCount + 0] = (CGLPixelFormatAttribute)1;
+        msaaAttributes[kAttributeCount + 1] = kCGLPFAMultisample;
+        msaaAttributes[kAttributeCount + 2] = kCGLPFASamples;
+        msaaAttributes[kAttributeCount + 3] =
+                                    (CGLPixelFormatAttribute)msaaSampleCount;
+        msaaAttributes[kAttributeCount + 4] = (CGLPixelFormatAttribute)0;
+        CGLChoosePixelFormat(msaaAttributes, &format, &npix);
+    }
+    if (!npix) {
+        CGLChoosePixelFormat(attributes, &format, &npix);
+    }
     
     CGLContextObj ctx;
     CGLCreateContext(format, NULL, &ctx);
@@ -267,9 +278,10 @@
         [fGLContext setView:self];
     }
 }
-- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType {
+- (bool)attach:(SkOSWindow::SkBackEndTypes)attachType
+        withMSAASampleCount:(int) sampleCount {
     if (nil == fGLContext) {
-        CGLContextObj ctx = createGLContext();
+        CGLContextObj ctx = createGLContext(sampleCount);
         fGLContext = [[NSOpenGLContext alloc] initWithCGLContextObj:ctx];
         CGLReleaseContext(ctx);
         if (NULL == fGLContext) {
diff --git a/src/views/mac/SkOSWindow_Mac.mm b/src/views/mac/SkOSWindow_Mac.mm
index 4aa4eb5..a5d3fef 100644
--- a/src/views/mac/SkOSWindow_Mac.mm
+++ b/src/views/mac/SkOSWindow_Mac.mm
@@ -63,8 +63,8 @@
     [(SkNSView*)fHWND onUpdateMenu:menu];
 }
 
-bool SkOSWindow::attach(SkBackEndTypes attachType) {
-    return [(SkNSView*)fHWND attach:attachType];
+bool SkOSWindow::attach(SkBackEndTypes attachType, int sampleCount) {
+    return [(SkNSView*)fHWND attach:attachType withMSAASampleCount:sampleCount];
 }
 
 void SkOSWindow::detach() {
diff --git a/src/views/unix/SkOSWindow_Unix.cpp b/src/views/unix/SkOSWindow_Unix.cpp
index 66b1694..c8fc2c7 100644
--- a/src/views/unix/SkOSWindow_Unix.cpp
+++ b/src/views/unix/SkOSWindow_Unix.cpp
@@ -34,53 +34,109 @@
 
 SkOSWindow::SkOSWindow(void* unused)
     : INHERITED()
-    , fVi(0) {
-    fUnixWindow.fDisplay = XOpenDisplay(NULL);
+    , fVi(NULL)
+    , fMSAASampleCount(0) {
+    fUnixWindow.fDisplay = NULL;
     fUnixWindow.fGLContext = NULL;
-    Display* dsp = fUnixWindow.fDisplay;
-    if (dsp) {
-        // Attempt to create a window that supports GL
-        GLint att[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER,
-                GLX_STENCIL_SIZE, 8, None };
-        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
-        if (fVi) {
-            Colormap colorMap = XCreateColormap(dsp, RootWindow(dsp, fVi->screen),
-                fVi->visual, AllocNone);
-            XSetWindowAttributes swa;
-            swa.colormap = colorMap;
-            swa.event_mask = EVENT_MASK;
-            fUnixWindow.fWin = XCreateWindow(dsp, RootWindow(dsp, fVi->screen),
-                    0, 0, WIDTH, HEIGHT, 0, fVi->depth,
-                    InputOutput, fVi->visual, CWEventMask | CWColormap, &swa);
-
-        } else {
-            // Create a simple window instead.  We will not be able to
-            // show GL
-            fUnixWindow.fWin = XCreateSimpleWindow(dsp, DefaultRootWindow(dsp),
-                    0, 0, WIDTH, HEIGHT, 0, 0, 0);
-        }
-        mapWindowAndWait();
-        fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
-    }
+    this->initWindow(0);
     this->resize(WIDTH, HEIGHT);
 }
 
 SkOSWindow::~SkOSWindow() {
+    this->closeWindow();
+}
+
+void SkOSWindow::closeWindow() {
     if (NULL != fUnixWindow.fDisplay) {
-        if (NULL != fUnixWindow.fGLContext) {
-            glXMakeCurrent(fUnixWindow.fDisplay, None, NULL);
-            glXDestroyContext(fUnixWindow.fDisplay, fUnixWindow.fGLContext);
-        }
+        this->detach();
+        SkASSERT(NULL != fUnixWindow.fGc);
         XFreeGC(fUnixWindow.fDisplay, fUnixWindow.fGc);
+        fUnixWindow.fGc = NULL;
         XDestroyWindow(fUnixWindow.fDisplay, fUnixWindow.fWin);
+        fVi = NULL;
         XCloseDisplay(fUnixWindow.fDisplay);
-        fUnixWindow.fDisplay = 0;
+        fUnixWindow.fDisplay = NULL;
+        fMSAASampleCount = 0;
     }
 }
 
+void SkOSWindow::initWindow(int requestedMSAASampleCount) {
+    if (fMSAASampleCount != requestedMSAASampleCount) {
+        this->closeWindow();
+    }
+    // presence of fDisplay means we already have a window
+    if (NULL != fUnixWindow.fDisplay) {
+        return;
+    }
+    fUnixWindow.fDisplay = XOpenDisplay(NULL);
+    Display* dsp = fUnixWindow.fDisplay;
+    if (NULL == dsp) {
+        SkDebugf("Could not open an X Display");
+        return;
+    }
+    // Attempt to create a window that supports GL
+    GLint att[] = {
+        GLX_RGBA,
+        GLX_DEPTH_SIZE, 24,
+        GLX_DOUBLEBUFFER,
+        GLX_STENCIL_SIZE, 8,
+        None
+    };
+    SkASSERT(NULL == fVi);
+    if (requestedMSAASampleCount > 0) {
+        static const GLint kAttCount = SK_ARRAY_COUNT(att);
+        GLint msaaAtt[kAttCount + 4];
+        memcpy(msaaAtt, att, sizeof(att));
+        SkASSERT(None == msaaAtt[kAttCount - 1]);
+        msaaAtt[kAttCount - 1] = GLX_SAMPLE_BUFFERS_ARB;
+        msaaAtt[kAttCount + 0] = 1;
+        msaaAtt[kAttCount + 1] = GLX_SAMPLES_ARB;
+        msaaAtt[kAttCount + 2] = requestedMSAASampleCount;
+        msaaAtt[kAttCount + 3] = None;
+        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), msaaAtt);
+        fMSAASampleCount = requestedMSAASampleCount;
+    }
+    if (NULL == fVi) {
+        fVi = glXChooseVisual(dsp, DefaultScreen(dsp), att);
+        fMSAASampleCount = 0;
+    }
+
+    if (fVi) {
+        Colormap colorMap = XCreateColormap(dsp,
+                                            RootWindow(dsp, fVi->screen),
+                                            fVi->visual,
+                                             AllocNone);
+        XSetWindowAttributes swa;
+        swa.colormap = colorMap;
+        swa.event_mask = EVENT_MASK;
+        fUnixWindow.fWin = XCreateWindow(dsp,
+                                         RootWindow(dsp, fVi->screen),
+                                         0, 0, // x, y
+                                         WIDTH, HEIGHT,
+                                         0, // border width
+                                         fVi->depth,
+                                         InputOutput,
+                                         fVi->visual,
+                                         CWEventMask | CWColormap,
+                                         &swa);
+    } else {
+        // Create a simple window instead.  We will not be able to show GL
+        fUnixWindow.fWin = XCreateSimpleWindow(dsp,
+                                               DefaultRootWindow(dsp),
+                                               0, 0,  // x, y
+                                               WIDTH, HEIGHT,
+                                               0,     // border width
+                                               0,     // border value
+                                               0);    // background value
+    }
+    this->mapWindowAndWait();
+    fUnixWindow.fGc = XCreateGC(dsp, fUnixWindow.fWin, 0, NULL);
+}
+
+
 void SkOSWindow::post_linuxevent() {
     // Put an event in the X queue to fire an SkEvent.
-    if (!fUnixWindow.fDisplay) {
+    if (NULL == fUnixWindow.fDisplay) {
         return;
     }
     long event_mask = NoEventMask;
@@ -97,6 +153,9 @@
 
 void SkOSWindow::loop() {
     Display* dsp = fUnixWindow.fDisplay;
+    if (NULL == dsp) {
+        return;
+    }
     XSelectInput(dsp, fUnixWindow.fWin, EVENT_MASK);
 
     bool loop = true;
@@ -153,6 +212,7 @@
 }
 
 void SkOSWindow::mapWindowAndWait() {
+    SkASSERT(NULL != fUnixWindow.fDisplay);
     Display* dsp = fUnixWindow.fDisplay;
     Window win = fUnixWindow.fWin;
     XMapWindow(dsp, win);
@@ -168,11 +228,13 @@
 
 }
 
-bool SkOSWindow::attach(SkBackEndTypes /* attachType */) {
+bool SkOSWindow::attach(SkBackEndTypes /* attachType */, int msaaSampleCount) {
+    this->initWindow(msaaSampleCount);
+    if (NULL == fUnixWindow.fDisplay) {
+        return false;
+    } 
     if (NULL == fUnixWindow.fGLContext) {
-        if (NULL == fUnixWindow.fDisplay || NULL == fVi) {
-            return false;
-        }
+        SkASSERT(NULL != fVi);
 
         fUnixWindow.fGLContext = glXCreateContext(fUnixWindow.fDisplay,
                                                   fVi,
@@ -209,7 +271,7 @@
 }
 
 void SkOSWindow::onSetTitle(const char title[]) {
-    if (!fUnixWindow.fDisplay) {
+    if (NULL == fUnixWindow.fDisplay) {
         return;
     }
     XTextProperty textProp;
@@ -253,16 +315,26 @@
 }
 
 void SkOSWindow::doPaint() {
-    if (!fUnixWindow.fDisplay) return;
+    if (NULL == fUnixWindow.fDisplay) {
+        return;
+    }
     // Draw the bitmap to the screen.
     const SkBitmap& bitmap = getBitmap();
     int width = bitmap.width();
     int height = bitmap.height();
 
     XImage image;
-    if (!convertBitmapToXImage(image, bitmap)) return;
+    if (!convertBitmapToXImage(image, bitmap)) {
+        return;
+    }
 
-    XPutImage(fUnixWindow.fDisplay, fUnixWindow.fWin, fUnixWindow.fGc, &image, 0, 0, 0, 0, width, height);
+    XPutImage(fUnixWindow.fDisplay,
+              fUnixWindow.fWin,
+              fUnixWindow.fGc,
+              &image,
+              0, 0,     // src x,y
+              0, 0,     // dst x,y
+              width, height);
 }
 
 bool SkOSWindow::onHandleChar(SkUnichar) {
diff --git a/src/views/win/SkOSWindow_win.cpp b/src/views/win/SkOSWindow_win.cpp
index d5aebea..6b26400 100644
--- a/src/views/win/SkOSWindow_win.cpp
+++ b/src/views/win/SkOSWindow_win.cpp
@@ -308,7 +308,7 @@
 
 #define USE_MSAA 0
 
-HGLRC create_gl(HWND hwnd) {
+HGLRC create_gl(HWND hwnd, int msaaSampleCount) {
 
     HDC dc = GetDC(hwnd);
 
@@ -323,7 +323,7 @@
 
     int format = 0;
 
-    GLint iattrs[] = {
+    static const GLint iAttrs[] = {
         SK_WGL_DRAW_TO_WINDOW, TRUE,
         SK_WGL_DOUBLE_BUFFER, TRUE,
         SK_WGL_ACCELERATION, SK_WGL_FULL_ACCELERATION,
@@ -331,40 +331,40 @@
         SK_WGL_COLOR_BITS, 24,
         SK_WGL_ALPHA_BITS, 8,
         SK_WGL_STENCIL_BITS, 8,
-
-        // these must be kept last
-        SK_WGL_SAMPLE_BUFFERS, TRUE,
-        SK_WGL_SAMPLES, 0,
-        0,0
+        0, 0
     };
 
-    static const int kSampleBuffersValueIdx = SK_ARRAY_COUNT(iattrs) - 5;
-    static const int kSamplesValueIdx = SK_ARRAY_COUNT(iattrs) - 3;
-    if (USE_MSAA && extensions.hasExtension(dc, "WGL_ARB_multisample")) {
-        for (int samples = 16; samples > 1; --samples) {
-            
-            iattrs[kSamplesValueIdx] = samples;
-            GLfloat fattrs[] = {0,0};
-            GLuint num;
-            int formats[64];
-            extensions.choosePixelFormat(dc, iattrs, fattrs, 64, formats, &num);
-            num = min(num,64);
-            for (GLuint i = 0; i < num; ++i) {
-                DescribePixelFormat(dc, formats[i], sizeof(pfd), &pfd);
-                if (SetPixelFormat(dc, formats[i], &pfd)) {
-                    format = formats[i];
-                    break;
-                }
+    GLfloat fAttrs[] = {0, 0};
+
+    if (msaaSampleCount > 0 &&
+        extensions.hasExtension(dc, "WGL_ARB_multisample")) {
+        static const int kIAttrsCount = SK_ARRAY_COUNT(iAttrs);
+        GLint msaaIAttrs[kIAttrsCount + 4];
+        memcpy(msaaIAttrs, iAttrs, sizeof(GLint) * 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;
+        GLuint num;
+        int formats[64];
+        extensions.choosePixelFormat(dc, msaaIAttrs, fAttrs, 64, formats, &num);
+        num = min(num,64);
+        for (GLuint i = 0; i < num; ++i) {
+            DescribePixelFormat(dc, formats[i], sizeof(pfd), &pfd);
+            if (SetPixelFormat(dc, formats[i], &pfd)) {
+                format = formats[i];
+                break;
             }
         }
     }
 
     if (0 == format) {
-        iattrs[kSampleBuffersValueIdx-1] = iattrs[kSampleBuffersValueIdx] = 0;
-        iattrs[kSamplesValueIdx-1] = iattrs[kSamplesValueIdx] = 0;
-        GLfloat fattrs[] = {0,0};
         GLuint num;
-        extensions.choosePixelFormat(dc, iattrs, fattrs, 1, &format, &num);
+        extensions.choosePixelFormat(dc, iAttrs, fAttrs, 1, &format, &num);
         DescribePixelFormat(dc, format, sizeof(pfd), &pfd);
         BOOL set = SetPixelFormat(dc, format, &pfd);
         SkASSERT(TRUE == set);
@@ -377,9 +377,9 @@
     return glrc;
 }
 
-bool SkOSWindow::attachGL() {
+bool SkOSWindow::attachGL(int msaaSampleCount) {
     if (NULL == fHGLRC) {
-        fHGLRC = create_gl((HWND)fHWND);
+        fHGLRC = create_gl((HWND)fHWND, msaaSampleCount);
         if (NULL == fHGLRC) {
             return false;
         }
@@ -408,13 +408,16 @@
 }
 
 #if SK_ANGLE
-bool create_ANGLE(EGLNativeWindowType hWnd, EGLDisplay* eglDisplay,
-                  EGLContext* eglContext, EGLSurface* eglSurface) {
-    EGLint contextAttribs[] = { 
-        EGL_CONTEXT_CLIENT_VERSION, 2, 
+bool create_ANGLE(EGLNativeWindowType hWnd,
+                  int msaaSampleCount,
+                  EGLDisplay* eglDisplay,
+                  EGLContext* eglContext,
+                  EGLSurface* eglSurface) {
+    static const EGLint contextAttribs[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
         EGL_NONE, EGL_NONE 
     };
-    EGLint configAttribList[] = {
+    static const EGLint configAttribList[] = {
         EGL_RED_SIZE,       8,
         EGL_GREEN_SIZE,     8,
         EGL_BLUE_SIZE,      8,
@@ -423,7 +426,7 @@
         EGL_STENCIL_SIZE,   8,
         EGL_NONE
     };
-    EGLint surfaceAttribList[] = {
+    static const EGLint surfaceAttribList[] = {
         EGL_NONE, EGL_NONE
     };
 
@@ -445,9 +448,31 @@
 
     // Choose config
     EGLConfig config;
-    if (!eglChooseConfig(display, configAttribList, 
-                                &config, 1, &numConfigs)) {
-       return false;
+    bool foundConfig = false;
+    if (msaaSampleCount) {
+        static const int kConfigAttribListCnt =
+                                SK_ARRAY_COUNT(configAttribList);
+        EGLint msaaConfigAttribList[kConfigAttribListCnt + 4];
+        memcpy(msaaConfigAttribList,
+               configAttribList,
+               sizeof(configAttribList));
+        SkASSERT(EGL_NONE == msaaConfigAttribList[kConfigAttribListCnt - 1]);
+        msaaConfigAttribList[kConfigAttribListCnt - 1] = EGL_SAMPLE_BUFFERS;
+        msaaConfigAttribList[kConfigAttribListCnt + 0] = 1;
+        msaaConfigAttribList[kConfigAttribListCnt + 1] = EGL_SAMPLES;
+        msaaConfigAttribList[kConfigAttribListCnt + 2] = msaaSampleCount;
+        msaaConfigAttribList[kConfigAttribListCnt + 3] = EGL_NONE;
+        if (eglChooseConfig(display, configAttribList,
+                                   &config, 1, &numConfigs)) {
+            SkASSERT(numConfigs > 0);
+            foundConfig = true;
+        }
+    }
+    if (!foundConfig) {
+        if (!eglChooseConfig(display, configAttribList, 
+                                    &config, 1, &numConfigs)) {
+           return false;
+        }
     }
 
     // Create a surface
@@ -477,9 +502,13 @@
     return true;
 }
 
-bool SkOSWindow::attachANGLE() {
+bool SkOSWindow::attachANGLE(int msaaSampleCount) {
     if (EGL_NO_DISPLAY == fDisplay) {
-        bool bResult = create_ANGLE((HWND)fHWND, &fDisplay, &fContext, &fSurface);
+        bool bResult = create_ANGLE((HWND)fHWND,
+                                    msaaSampleCount,
+                                    &fDisplay,
+                                    &fContext,
+                                    &fSurface);
         if (false == bResult) {
             return false;
         }
@@ -489,7 +518,7 @@
             GR_GL_CALL(intf, ClearStencil(0));
             GR_GL_CALL(intf, ClearColor(0, 0, 0, 0));
             GR_GL_CALL(intf, StencilMask(0xffffffff));
-            GR_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT));
+            GR_GL_CALL(intf, Clear(GL_STENCIL_BUFFER_BIT |GL_COLOR_BUFFER_BIT));
         }
     }
     if (eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
@@ -529,7 +558,7 @@
 #endif
 
 // return true on success
-bool SkOSWindow::attach(SkBackEndTypes attachType) {
+bool SkOSWindow::attach(SkBackEndTypes attachType, int msaaSampleCount) {
 
     // attach doubles as "windowResize" so we need to allo
     // already bound states to pass through again
@@ -542,11 +571,11 @@
         // nothing to do
         break; 
     case kNativeGL_BackEndType:
-        result = attachGL();
+        result = attachGL(msaaSampleCount);
         break;
 #if SK_ANGLE
     case kANGLE_BackEndType:
-        result = attachANGLE();
+        result = attachANGLE(msaaSampleCount);
         break;
 #endif
     default: