Support multisampled framebuffers with the GL backend.

Move validation of sample counts into the Renderbuffer implementations
because the exact supported sample counts are not always known.

BUG=angleoproject:886

Change-Id: I9c90d9d435e940b852343a29a6aa11d6cb1ad23b
Reviewed-on: https://chromium-review.googlesource.com/255513
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Caps.h b/src/libANGLE/Caps.h
index cbdfe63..3daf5b5 100644
--- a/src/libANGLE/Caps.h
+++ b/src/libANGLE/Caps.h
@@ -33,6 +33,7 @@
     // Support for being used as a framebuffer attachment or renderbuffer format
     bool renderable;
 
+    // Set of supported sample counts, only guaranteed to be valid in ES3.
     SupportedSampleSet sampleCounts;
 
     // Get the maximum number of samples supported
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 689c602..a79cf2d 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -1548,7 +1548,6 @@
 
     mCaps.maxFragmentInputComponents = std::min<GLuint>(mCaps.maxFragmentInputComponents, IMPLEMENTATION_MAX_VARYING_VECTORS * 4);
 
-    GLuint maxSamples = 0;
     mCaps.compressedTextureFormats.clear();
 
     const TextureCapsMap &rendererFormats = mRenderer->getRendererTextureCaps();
@@ -1569,7 +1568,6 @@
         {
             formatCaps.sampleCounts.clear();
         }
-        maxSamples = std::max(maxSamples, formatCaps.getMaxSamples());
 
         if (formatCaps.texturable && formatInfo.compressed)
         {
@@ -1578,8 +1576,6 @@
 
         mTextureCaps.insert(format, formatCaps);
     }
-
-    mCaps.maxSamples = maxSamples;
 }
 
 Data Context::getData() const
diff --git a/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp b/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
index c7f3c4c..1a44161 100644
--- a/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RenderbufferD3D.cpp
@@ -41,6 +41,17 @@
         creationFormat = GL_DEPTH24_STENCIL8_OES;
     }
 
+    // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
+    // the specified storage.
+    // Because ES 3.0 already knows the exact number of supported samples, it would already have been
+    // validated and generated GL_INVALID_VALUE.
+    const gl::TextureCaps &formatCaps = mRenderer->getRendererTextureCaps().get(creationFormat);
+    if (samples > formatCaps.getMaxSamples())
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Renderbuffer format does not support %u samples, %u is the maximum.",
+                         samples, formatCaps.getMaxSamples());
+    }
+
     RenderTargetD3D *newRT = NULL;
     gl::Error error = mRenderer->createRenderTarget(width, height, creationFormat, samples, &newRT);
     if (error.isError())
diff --git a/src/libANGLE/renderer/gl/FunctionsGL.cpp b/src/libANGLE/renderer/gl/FunctionsGL.cpp
index a56dec1..cc20bda 100644
--- a/src/libANGLE/renderer/gl/FunctionsGL.cpp
+++ b/src/libANGLE/renderer/gl/FunctionsGL.cpp
@@ -7,18 +7,89 @@
 // FunctionsGL.cpp: Implements the FuntionsGL class to contain loaded GL functions
 
 #include "libANGLE/renderer/gl/FunctionsGL.h"
+#include "libANGLE/renderer/gl/renderergl_utils.h"
 
 namespace rx
 {
 
+static void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion,
+                         bool *outIsES)
+{
+    const std::string version = reinterpret_cast<const char*>(getStringFunction(GL_VERSION));
+    if (version.find("OpenGL ES") == std::string::npos)
+    {
+        // ES spec states that the GL_VERSION string will be in the following format:
+        // "OpenGL ES N.M vendor-specific information"
+        *outIsES = false;
+        *outMajorVersion = version[0] - '0';
+        *outMinorVersion = version[2] - '0';
+    }
+    else
+    {
+        // OpenGL spec states the GL_VERSION string will be in the following format:
+        // <version number><space><vendor-specific information>
+        // The version number is either of the form major number.minor number or major
+        // number.minor number.release number, where the numbers all have one or more
+        // digits
+        *outIsES = true;
+        *outMajorVersion = version[10] - '0';
+        *outMinorVersion = version[12] - '0';
+    }
+}
+
+static std::vector<std::string> GetNonIndexedExtensions(PFNGLGETSTRINGPROC getStringFunction)
+{
+    std::vector<std::string> result;
+
+    std::istringstream stream(reinterpret_cast<const char*>(getStringFunction(GL_EXTENSIONS)));
+    std::string extension;
+    while (std::getline(stream, extension, ' '))
+    {
+        result.push_back(extension);
+    }
+
+    return result;
+}
+
+static std::vector<std::string> GetIndexedExtensions(PFNGLGETINTEGERVPROC getIntegerFunction, PFNGLGETSTRINGIPROC getStringIFunction)
+{
+    std::vector<std::string> result;
+
+    GLint numExtensions;
+    getIntegerFunction(GL_NUM_EXTENSIONS, &numExtensions);
+
+    result.reserve(numExtensions);
+
+    for (GLint i = 0; i < numExtensions; i++)
+    {
+        result.push_back(reinterpret_cast<const char*>(getStringIFunction(GL_EXTENSIONS, i)));
+    }
+
+    return result;
+}
+
 template <typename T>
 static void AssignGLEntryPoint(void *function, T *outFunction)
 {
     *outFunction = reinterpret_cast<T>(function);
 }
 
+template <typename T>
+static void AssignGLExtensionEntryPoint(const std::vector<std::string> &extensions, const std::string &extension, void *function, T *outFunction)
+{
+    if (std::find(extensions.begin(), extensions.end(), extension) != extensions.end())
+    {
+        *outFunction = reinterpret_cast<T>(function);
+    }
+}
+
 FunctionsGL::FunctionsGL()
-    : blendFunc(nullptr),
+    : majorVersion(0),
+      minorVersion(0),
+      openGLES(false),
+      extensions(),
+
+      blendFunc(nullptr),
       clear(nullptr),
       clearColor(nullptr),
       clearDepth(nullptr),
@@ -694,8 +765,24 @@
 {
 }
 
-void FunctionsGL::initialize(GLuint majorVersion, GLuint minorVersion)
+void FunctionsGL::initialize()
 {
+    // Grab the version number
+    AssignGLEntryPoint(loadProcAddress("glGetString"), &getString);
+    GetGLVersion(getString, &majorVersion, &minorVersion, &openGLES);
+
+    // Grab the GL extensions
+    if (majorVersion > 3 || majorVersion == 3 && minorVersion >= 0)
+    {
+        AssignGLEntryPoint(loadProcAddress("glGetIntegerv"), &getIntegerv);
+        AssignGLEntryPoint(loadProcAddress("glGetStringi"), &getStringi);
+        extensions = GetIndexedExtensions(getIntegerv, getStringi);
+    }
+    else
+    {
+        extensions = GetNonIndexedExtensions(getString);
+    }
+
     // 1.0
     if (majorVersion > 1 || majorVersion == 1 && minorVersion >= 0)
     {
@@ -1024,6 +1111,9 @@
         AssignGLEntryPoint(loadProcAddress("glVertexAttribI4uiv"), &vertexAttribI4uiv);
         AssignGLEntryPoint(loadProcAddress("glVertexAttribI4usv"), &vertexAttribI4usv);
         AssignGLEntryPoint(loadProcAddress("glVertexAttribIPointer"), &vertexAttribIPointer);
+
+        // Extensions
+        AssignGLExtensionEntryPoint(extensions, "GL_ARB_internalformat_query", loadProcAddress("glGetInternalformativ"), &getInternalformativ);
     }
 
     // 3.1
diff --git a/src/libANGLE/renderer/gl/FunctionsGL.h b/src/libANGLE/renderer/gl/FunctionsGL.h
index 6da9aa6..f479086 100644
--- a/src/libANGLE/renderer/gl/FunctionsGL.h
+++ b/src/libANGLE/renderer/gl/FunctionsGL.h
@@ -22,8 +22,17 @@
     FunctionsGL();
     virtual ~FunctionsGL();
 
-    void initialize(GLuint majorVersion, GLuint minorVersion);
+    void initialize();
 
+    // Version information
+    GLuint majorVersion;
+    GLuint minorVersion;
+    bool openGLES;
+
+    // Extensions
+    std::vector<std::string> extensions;
+
+    // Entry Points
     // 1.0
     PFNGLBLENDFUNCPROC blendFunc;
     PFNGLCLEARPROC clear;
diff --git a/src/libANGLE/renderer/gl/RenderbufferGL.cpp b/src/libANGLE/renderer/gl/RenderbufferGL.cpp
index b580ea8..823c0ea 100644
--- a/src/libANGLE/renderer/gl/RenderbufferGL.cpp
+++ b/src/libANGLE/renderer/gl/RenderbufferGL.cpp
@@ -9,17 +9,20 @@
 #include "libANGLE/renderer/gl/RenderbufferGL.h"
 
 #include "common/debug.h"
+#include "libANGLE/Caps.h"
 #include "libANGLE/angletypes.h"
 #include "libANGLE/renderer/gl/FunctionsGL.h"
 #include "libANGLE/renderer/gl/StateManagerGL.h"
+#include "libANGLE/renderer/gl/renderergl_utils.h"
 
 namespace rx
 {
 
-RenderbufferGL::RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager)
+RenderbufferGL::RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps)
     : RenderbufferImpl(),
       mFunctions(functions),
       mStateManager(stateManager),
+      mTextureCaps(textureCaps),
       mRenderbufferID(0)
 {
     mFunctions->genRenderbuffers(1, &mRenderbufferID);
@@ -45,6 +48,25 @@
 {
     mStateManager->bindRenderbuffer(GL_RENDERBUFFER, mRenderbufferID);
     mFunctions->renderbufferStorageMultisample(GL_RENDERBUFFER, samples, internalformat, width, height);
+
+    const gl::TextureCaps &formatCaps = mTextureCaps.get(internalformat);
+    if (samples > formatCaps.getMaxSamples())
+    {
+        // Before version 4.2, it is unknown if the specific internal format can support the requested number
+        // of samples.  It is expected that GL_OUT_OF_MEMORY is returned if the renderbuffer cannot be created.
+        GLenum error = GL_NO_ERROR;
+        do
+        {
+            GLenum error = mFunctions->getError();
+            if (error == GL_OUT_OF_MEMORY)
+            {
+                return gl::Error(GL_OUT_OF_MEMORY);
+            }
+
+            ASSERT(error == GL_NO_ERROR);
+        } while (error != GL_NO_ERROR);
+    }
+
     return gl::Error(GL_NO_ERROR);
 }
 
diff --git a/src/libANGLE/renderer/gl/RenderbufferGL.h b/src/libANGLE/renderer/gl/RenderbufferGL.h
index 46d1571..876318a 100644
--- a/src/libANGLE/renderer/gl/RenderbufferGL.h
+++ b/src/libANGLE/renderer/gl/RenderbufferGL.h
@@ -11,6 +11,11 @@
 
 #include "libANGLE/renderer/RenderbufferImpl.h"
 
+namespace gl
+{
+class TextureCapsMap;
+}
+
 namespace rx
 {
 
@@ -20,7 +25,7 @@
 class RenderbufferGL : public RenderbufferImpl
 {
   public:
-    RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager);
+    RenderbufferGL(const FunctionsGL *functions, StateManagerGL *stateManager, const gl::TextureCapsMap &textureCaps);
     ~RenderbufferGL() override;
 
     virtual gl::Error setStorage(GLenum internalformat, size_t width, size_t height) override;
@@ -31,6 +36,7 @@
   private:
     const FunctionsGL *mFunctions;
     StateManagerGL *mStateManager;
+    const gl::TextureCapsMap &mTextureCaps;
 
     GLuint mRenderbufferID;
 };
diff --git a/src/libANGLE/renderer/gl/RendererGL.cpp b/src/libANGLE/renderer/gl/RendererGL.cpp
index a8c5ef7..b4abac6 100644
--- a/src/libANGLE/renderer/gl/RendererGL.cpp
+++ b/src/libANGLE/renderer/gl/RendererGL.cpp
@@ -124,7 +124,7 @@
 
 RenderbufferImpl *RendererGL::createRenderbuffer()
 {
-    return new RenderbufferGL(mFunctions, mStateManager);
+    return new RenderbufferGL(mFunctions, mStateManager, getRendererTextureCaps());
 }
 
 BufferImpl *RendererGL::createBuffer()
@@ -196,18 +196,13 @@
     std::string nativeVendorString(reinterpret_cast<const char*>(mFunctions->getString(GL_VENDOR)));
     std::string nativeRendererString(reinterpret_cast<const char*>(mFunctions->getString(GL_RENDERER)));
 
-    GLuint major;
-    GLuint minor;
-    bool isES;
-    nativegl::GetGLVersion(mFunctions->getString, &major, &minor, &isES);
-
     std::ostringstream rendererString;
     rendererString << nativeVendorString << " " << nativeRendererString << " OpenGL";
-    if (isES)
+    if (mFunctions->openGLES)
     {
         rendererString << " ES";
     }
-    rendererString << " " << major << "." << minor;
+    rendererString << " " << mFunctions->majorVersion << "." << mFunctions->minorVersion;
 
     return rendererString.str();
 }
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index d7ba1ce..433aee2 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -21,62 +21,35 @@
 namespace rx
 {
 
-namespace nativegl
-{
-
-void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion,
-                  bool *outIsES)
-{
-    const std::string version = reinterpret_cast<const char*>(getStringFunction(GL_VERSION));
-    if (version.find("OpenGL ES") == std::string::npos)
-    {
-        // ES spec states that the GL_VERSION string will be in the following format:
-        // "OpenGL ES N.M vendor-specific information"
-        *outIsES = false;
-        *outMajorVersion = version[0] - '0';
-        *outMinorVersion = version[2] - '0';
-    }
-    else
-    {
-        // OpenGL spec states the GL_VERSION string will be in the following format:
-        // <version number><space><vendor-specific information>
-        // The version number is either of the form major number.minor number or major
-        // number.minor number.release number, where the numbers all have one or more
-        // digits
-        *outIsES = true;
-        *outMajorVersion = version[10] - '0';
-        *outMinorVersion = version[12] - '0';
-    }
-}
-
-std::vector<std::string> GetGLExtensions(PFNGLGETSTRINGPROC getStringFunction)
-{
-    std::vector<std::string> result;
-
-    std::istringstream stream(reinterpret_cast<const char*>(getStringFunction(GL_EXTENSIONS)));
-    std::string extension;
-    while (std::getline(stream, extension, ' '))
-    {
-        result.push_back(extension);
-    }
-
-    return result;
-}
-
-}
-
 namespace nativegl_gl
 {
 
-static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, GLenum internalFormat, GLuint majorVersion, GLuint minorVersion,
-                                                 const std::vector<std::string> &extensions)
+static gl::TextureCaps GenerateTextureFormatCaps(const FunctionsGL *functions, GLenum internalFormat)
 {
     gl::TextureCaps textureCaps;
 
     const nativegl::InternalFormat &formatInfo = nativegl::GetInternalFormatInfo(internalFormat);
-    textureCaps.texturable = formatInfo.textureSupport(majorVersion, minorVersion, extensions);
-    textureCaps.renderable = formatInfo.renderSupport(majorVersion, minorVersion, extensions);
-    textureCaps.filterable = formatInfo.filterSupport(majorVersion, minorVersion, extensions);
+    textureCaps.texturable = formatInfo.textureSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
+    textureCaps.renderable = formatInfo.renderSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
+    textureCaps.filterable = formatInfo.filterSupport(functions->majorVersion, functions->minorVersion, functions->extensions);
+
+    // glGetInternalformativ is not available until version 4.2 but may be available through the 3.0
+    // extension GL_ARB_internalformat_query
+    if (textureCaps.renderable && functions->getInternalformativ)
+    {
+        GLint numSamples = 0;
+        functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_NUM_SAMPLE_COUNTS, 1, &numSamples);
+
+        if (numSamples > 0)
+        {
+            std::vector<GLint> samples(numSamples);
+            functions->getInternalformativ(GL_RENDERBUFFER, internalFormat, GL_SAMPLES, samples.size(), &samples[0]);
+            for (size_t sampleIndex = 0; sampleIndex < samples.size(); sampleIndex++)
+            {
+                textureCaps.sampleCounts.insert(samples[sampleIndex]);
+            }
+        }
+    }
 
     return textureCaps;
 }
@@ -91,23 +64,13 @@
 void GenerateCaps(const FunctionsGL *functions, gl::Caps *caps, gl::TextureCapsMap *textureCapsMap,
                   gl::Extensions *extensions)
 {
-    GLuint majorVersion = 0;
-    GLuint minorVersion = 0;
-    bool isES = false;
-    nativegl::GetGLVersion(functions->getString, &majorVersion, &minorVersion, &isES);
-
-    std::vector<std::string> nativeExtensions = nativegl::GetGLExtensions(functions->getString);
-
     // Texture format support checks
-    GLuint maxSamples = 0;
     const gl::FormatSet &allFormats = gl::GetAllSizedInternalFormats();
     for (GLenum internalFormat : allFormats)
     {
-        gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat, majorVersion, minorVersion, nativeExtensions);
+        gl::TextureCaps textureCaps = GenerateTextureFormatCaps(functions, internalFormat);
         textureCapsMap->insert(internalFormat, textureCaps);
 
-        maxSamples = std::max(maxSamples, textureCaps.getMaxSamples());
-
         if (gl::GetInternalFormatInfo(internalFormat).compressed)
         {
             caps->compressedTextureFormats.push_back(internalFormat);
@@ -184,13 +147,14 @@
     caps->maxTransformFeedbackSeparateComponents = 4;
 
     // Table 6.35, Framebuffer Dependent Values
-    caps->maxSamples = 4;
+    caps->maxSamples = QuerySingleGLInt(functions, GL_MAX_SAMPLES);
 
     // Extension support
     extensions->setTextureExtensionSupport(*textureCapsMap);
     extensions->textureNPOT = true;
     extensions->textureStorage = true;
     extensions->fboRenderMipmap = true;
+    extensions->framebufferMultisample = caps->maxSamples > 0;
 }
 
 }
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.h b/src/libANGLE/renderer/gl/renderergl_utils.h
index 0e028c9..3a6fa4d 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.h
+++ b/src/libANGLE/renderer/gl/renderergl_utils.h
@@ -25,14 +25,6 @@
 {
 class FunctionsGL;
 
-namespace nativegl
-{
-
-void GetGLVersion(PFNGLGETSTRINGPROC getStringFunction, GLuint *outMajorVersion, GLuint *outMinorVersion, bool *outIsES);
-std::vector<std::string> GetGLExtensions(PFNGLGETSTRINGPROC getStringFunction);
-
-}
-
 namespace nativegl_gl
 {
 
diff --git a/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp b/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
index a7ff405..6180f35 100644
--- a/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
+++ b/src/libANGLE/renderer/gl/wgl/DisplayWGL.cpp
@@ -58,8 +58,6 @@
 DisplayWGL::DisplayWGL()
     : DisplayGL(),
       mOpenGLModule(nullptr),
-      mGLVersionMajor(0),
-      mGLVersionMinor(0),
       mFunctionsWGL(nullptr),
       mFunctionsGL(nullptr),
       mWindowClass(0),
@@ -186,12 +184,6 @@
         return egl::Error(EGL_NOT_INITIALIZED, "Failed to get glGetString pointer.");
     }
 
-    GLuint maxGLVersionMajor = 0;
-    GLuint maxGLVersionMinor = 0;
-    bool isES = false;
-    nativegl::GetGLVersion(getString, &maxGLVersionMajor, &maxGLVersionMinor, &isES);
-    ASSERT(!isES);
-
     // Reinitialize the wgl functions to grab the extensions
     mFunctionsWGL->intialize(mOpenGLModule, dummyDeviceContext);
 
@@ -283,9 +275,6 @@
     if (!mWGLContext)
     {
         // Don't have control over GL versions
-        mGLVersionMajor = maxGLVersionMajor;
-        mGLVersionMinor = maxGLVersionMinor;
-
         mWGLContext = mFunctionsWGL->createContext(mDeviceContext);
     }
 
@@ -299,11 +288,8 @@
         return egl::Error(EGL_NOT_INITIALIZED, "Failed to make the intermediate WGL context current.");
     }
 
-    nativegl::GetGLVersion(getString, &mGLVersionMajor, &mGLVersionMinor, &isES);
-    ASSERT(!isES);
-
     mFunctionsGL = new FunctionsGLWindows(mOpenGLModule, mFunctionsWGL->getProcAddress);
-    mFunctionsGL->initialize(mGLVersionMajor, mGLVersionMinor);
+    mFunctionsGL->initialize();
 
     return DisplayGL::initialize(display);
 }
diff --git a/src/libANGLE/renderer/gl/wgl/DisplayWGL.h b/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
index 75be07b..75de2a2 100644
--- a/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
+++ b/src/libANGLE/renderer/gl/wgl/DisplayWGL.h
@@ -55,8 +55,6 @@
     void generateCaps(egl::Caps *outCaps) const override;
 
     HMODULE mOpenGLModule;
-    GLuint mGLVersionMajor;
-    GLuint mGLVersionMinor;
 
     FunctionsWGL *mFunctionsWGL;
     FunctionsGL *mFunctionsGL;
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index b1685c7..6aaf698 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -362,11 +362,15 @@
     // ANGLE_framebuffer_multisample states GL_OUT_OF_MEMORY is generated on a failure to create
     // the specified storage. This is different than ES 3.0 in which a sample number higher
     // than the maximum sample number supported  by this format generates a GL_INVALID_VALUE.
-    const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
-    if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
+    // The TextureCaps::getMaxSamples method is only guarenteed to be valid when the context is ES3.
+    if (context->getClientVersion() >= 3)
     {
-        context->recordError(Error(GL_OUT_OF_MEMORY));
-        return false;
+        const TextureCaps &formatCaps = context->getTextureCaps().get(internalformat);
+        if (static_cast<GLuint>(samples) > formatCaps.getMaxSamples())
+        {
+            context->recordError(Error(GL_OUT_OF_MEMORY));
+            return false;
+        }
     }
 
     return ValidateRenderbufferStorageParametersBase(context, target, samples, internalformat, width, height);