GLES: Expose OES_mapbuffer in GLES2 on GLES3.

This extension is mandatory for EXT_map_buffer_range support. We can
emulate it using GLES 3.0 core map functionality.

BUG=angleproject:1751

Change-Id: Idba09ce7276603d5556039f4a49aa0b87cae22aa
Reviewed-on: https://chromium-review.googlesource.com/431826
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/renderer/gl/BufferGL.cpp b/src/libANGLE/renderer/gl/BufferGL.cpp
index 9dfd076..2de2b3e 100644
--- a/src/libANGLE/renderer/gl/BufferGL.cpp
+++ b/src/libANGLE/renderer/gl/BufferGL.cpp
@@ -115,11 +115,18 @@
     {
         *mapPtr = mShadowCopy.data();
     }
-    else
+    else if (mFunctions->mapBuffer)
     {
         mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
         *mapPtr = mFunctions->mapBuffer(DestBufferOperationTarget, access);
     }
+    else
+    {
+        ASSERT(mFunctions->mapBufferRange && access == GL_WRITE_ONLY_OES);
+        mStateManager->bindBuffer(DestBufferOperationTarget, mBufferID);
+        *mapPtr =
+            mFunctions->mapBufferRange(DestBufferOperationTarget, 0, mBufferSize, GL_MAP_WRITE_BIT);
+    }
 
     mIsMapped = true;
     mMapOffset = 0;
diff --git a/src/libANGLE/renderer/gl/renderergl_utils.cpp b/src/libANGLE/renderer/gl/renderergl_utils.cpp
index 26f44da..217ac77 100644
--- a/src/libANGLE/renderer/gl/renderergl_utils.cpp
+++ b/src/libANGLE/renderer/gl/renderergl_utils.cpp
@@ -788,6 +788,7 @@
     extensions->readFormatBGRA = functions->isAtLeastGL(gl::Version(1, 2)) || functions->hasGLExtension("GL_EXT_bgra") ||
                                  functions->hasGLESExtension("GL_EXT_read_format_bgra");
     extensions->mapBuffer = functions->isAtLeastGL(gl::Version(1, 5)) ||
+                            functions->isAtLeastGLES(gl::Version(3, 0)) ||
                             functions->hasGLESExtension("GL_OES_mapbuffer");
     extensions->mapBufferRange = functions->isAtLeastGL(gl::Version(3, 0)) || functions->hasGLExtension("GL_ARB_map_buffer_range") ||
                                  functions->isAtLeastGLES(gl::Version(3, 0)) || functions->hasGLESExtension("GL_EXT_map_buffer_range");
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 3d9dba3..3607de6 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -1230,7 +1230,7 @@
             if (!extensions.mapBuffer)
             {
                 context->handleError(
-                    Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_map_buffer."));
+                    Error(GL_INVALID_ENUM, "pname requires OpenGL ES 3.0 or GL_OES_mapbuffer."));
                 return false;
             }
             break;
@@ -1242,7 +1242,7 @@
             {
                 context->handleError(Error(
                     GL_INVALID_ENUM,
-                    "pname requires OpenGL ES 3.0, GL_OES_map_buffer or GL_EXT_map_buffer_range."));
+                    "pname requires OpenGL ES 3.0, GL_OES_mapbuffer or GL_EXT_map_buffer_range."));
                 return false;
             }
             break;
@@ -4366,7 +4366,7 @@
     {
         context->handleError(
             Error(GL_INVALID_OPERATION,
-                  "Context does not support OpenGL ES 3.0 or GL_OES_map_buffer is not enabled."));
+                  "Context does not support OpenGL ES 3.0 or GL_OES_mapbuffer is not enabled."));
         return false;
     }
 
diff --git a/src/tests/gl_tests/BufferDataTest.cpp b/src/tests/gl_tests/BufferDataTest.cpp
index 7707a4a..5ba705d 100644
--- a/src/tests/gl_tests/BufferDataTest.cpp
+++ b/src/tests/gl_tests/BufferDataTest.cpp
@@ -7,6 +7,8 @@
 #include "test_utils/ANGLETest.h"
 #include "test_utils/gl_raii.h"
 
+#include "random_utils.h"
+
 #include <stdint.h>
 
 using namespace angle;
@@ -433,6 +435,54 @@
     EXPECT_GL_NO_ERROR();
 }
 
+// Verify OES_mapbuffer is present if EXT_map_buffer_range is.
+TEST_P(BufferDataTest, ExtensionDependency)
+{
+    if (extensionEnabled("GL_EXT_map_buffer_range"))
+    {
+        ASSERT_TRUE(extensionEnabled("GL_OES_mapbuffer"));
+    }
+}
+
+// Test mapping with the OES extension.
+TEST_P(BufferDataTest, MapBufferOES)
+{
+    if (!extensionEnabled("GL_EXT_map_buffer_range"))
+    {
+        // Needed for test validation.
+        return;
+    }
+
+    std::vector<uint8_t> data(1024);
+    FillVectorWithRandomUBytes(&data);
+
+    GLBuffer buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
+    glBufferData(GL_ARRAY_BUFFER, data.size(), nullptr, GL_STATIC_DRAW);
+
+    // Validate that other map flags don't work.
+    void *badMapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_MAP_READ_BIT);
+    EXPECT_EQ(nullptr, badMapPtr);
+    EXPECT_GL_ERROR(GL_INVALID_ENUM);
+
+    // Map and write.
+    void *mapPtr = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
+    ASSERT_NE(nullptr, mapPtr);
+    ASSERT_GL_NO_ERROR();
+    memcpy(mapPtr, data.data(), data.size());
+    glUnmapBufferOES(GL_ARRAY_BUFFER);
+
+    // Validate data with EXT_map_buffer_range
+    void *readMapPtr = glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, data.size(), GL_MAP_READ_BIT_EXT);
+    ASSERT_NE(nullptr, readMapPtr);
+    ASSERT_GL_NO_ERROR();
+    std::vector<uint8_t> actualData(data.size());
+    memcpy(actualData.data(), readMapPtr, data.size());
+    glUnmapBufferOES(GL_ARRAY_BUFFER);
+
+    EXPECT_EQ(data, actualData);
+}
+
 // Use this to select which configurations (e.g. which renderer, which GLES major version) these tests should be run against.
 ANGLE_INSTANTIATE_TEST(BufferDataTest, ES2_D3D9(), ES2_D3D11(), ES2_OPENGL(), ES2_OPENGLES());
 ANGLE_INSTANTIATE_TEST(BufferDataTestES3, ES3_D3D11(), ES3_OPENGL(), ES3_OPENGLES());
diff --git a/src/tests/gl_tests/SimpleOperationTest.cpp b/src/tests/gl_tests/SimpleOperationTest.cpp
index b11fb9f..4806abd 100644
--- a/src/tests/gl_tests/SimpleOperationTest.cpp
+++ b/src/tests/gl_tests/SimpleOperationTest.cpp
@@ -10,6 +10,9 @@
 
 #include <vector>
 
+#include "random_utils.h"
+#include "test_utils/gl_raii.h"
+
 using namespace angle;
 
 namespace
@@ -27,8 +30,28 @@
         setConfigBlueBits(8);
         setConfigAlphaBits(8);
     }
+
+    void verifyBuffer(const std::vector<uint8_t> &data, GLenum binding);
 };
 
+void SimpleOperationTest::verifyBuffer(const std::vector<uint8_t> &data, GLenum binding)
+{
+    if (!extensionEnabled("GL_EXT_map_buffer_range"))
+    {
+        return;
+    }
+
+    uint8_t *mapPointer =
+        static_cast<uint8_t *>(glMapBufferRangeEXT(GL_ARRAY_BUFFER, 0, 1024, GL_MAP_READ_BIT));
+    ASSERT_GL_NO_ERROR();
+
+    std::vector<uint8_t> readbackData(data.size());
+    memcpy(readbackData.data(), mapPointer, data.size());
+    glUnmapBufferOES(GL_ARRAY_BUFFER);
+
+    EXPECT_EQ(data, readbackData);
+}
+
 TEST_P(SimpleOperationTest, CompileVertexShader)
 {
     const std::string source = SHADER_SOURCE
@@ -154,46 +177,47 @@
 
 TEST_P(SimpleOperationTest, BufferDataWithData)
 {
-    GLuint buffer;
-    glGenBuffers(1, &buffer);
-    glBindBuffer(GL_ARRAY_BUFFER, buffer);
+    GLBuffer buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
 
     std::vector<uint8_t> data(1024);
+    FillVectorWithRandomUBytes(&data);
     glBufferData(GL_ARRAY_BUFFER, data.size(), &data[0], GL_STATIC_DRAW);
 
-    glDeleteBuffers(1, &buffer);
+    verifyBuffer(data, GL_ARRAY_BUFFER);
 
     EXPECT_GL_NO_ERROR();
 }
 
 TEST_P(SimpleOperationTest, BufferDataWithNoData)
 {
-    GLuint buffer;
-    glGenBuffers(1, &buffer);
-    glBindBuffer(GL_ARRAY_BUFFER, buffer);
+    GLBuffer buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
     glBufferData(GL_ARRAY_BUFFER, 1024, nullptr, GL_STATIC_DRAW);
-    glDeleteBuffers(1, &buffer);
 
     EXPECT_GL_NO_ERROR();
 }
 
 TEST_P(SimpleOperationTest, BufferSubData)
 {
-    GLuint buffer;
-    glGenBuffers(1, &buffer);
-    glBindBuffer(GL_ARRAY_BUFFER, buffer);
+    GLBuffer buffer;
+    glBindBuffer(GL_ARRAY_BUFFER, buffer.get());
 
-    const size_t bufferSize = 1024;
+    constexpr size_t bufferSize = 1024;
+    std::vector<uint8_t> data(bufferSize);
+    FillVectorWithRandomUBytes(&data);
+
     glBufferData(GL_ARRAY_BUFFER, bufferSize, nullptr, GL_STATIC_DRAW);
 
-    const size_t subDataCount = 16;
-    std::vector<uint8_t> data(bufferSize / subDataCount);
+    constexpr size_t subDataCount = 16;
+    constexpr size_t sliceSize    = bufferSize / subDataCount;
     for (size_t i = 0; i < subDataCount; i++)
     {
-        glBufferSubData(GL_ARRAY_BUFFER, data.size() * i, data.size(), &data[0]);
+        size_t offset = i * sliceSize;
+        glBufferSubData(GL_ARRAY_BUFFER, offset, sliceSize, &data[offset]);
     }
 
-    glDeleteBuffers(1, &buffer);
+    verifyBuffer(data, GL_ARRAY_BUFFER);
 
     EXPECT_GL_NO_ERROR();
 }