OpenGL: implement occlusion queries.

On ResolveQuerySet(), get all available query results into a CPU-side
vector.  Copy the results from there to the destination buffer.

Bug: dawn:2186
Change-Id: I49c58ff611633ca5362de679e27e260dcb9759e1
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/160780
Commit-Queue: Stephen White <senorblanco@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/dawn/native/opengl/CommandBufferGL.cpp b/src/dawn/native/opengl/CommandBufferGL.cpp
index f6bd10e..be89cf9 100644
--- a/src/dawn/native/opengl/CommandBufferGL.cpp
+++ b/src/dawn/native/opengl/CommandBufferGL.cpp
@@ -44,6 +44,7 @@
 #include "dawn/native/opengl/Forward.h"
 #include "dawn/native/opengl/PersistentPipelineStateGL.h"
 #include "dawn/native/opengl/PipelineLayoutGL.h"
+#include "dawn/native/opengl/QuerySetGL.h"
 #include "dawn/native/opengl/RenderPipelineGL.h"
 #include "dawn/native/opengl/SamplerGL.h"
 #include "dawn/native/opengl/TextureGL.h"
@@ -825,8 +826,30 @@
             }
 
             case Command::ResolveQuerySet: {
-                // TODO(crbug.com/dawn/434): Resolve non-precise occlusion query.
-                SkipCommand(&mCommands, type);
+                ResolveQuerySetCmd* cmd = mCommands.NextCommand<ResolveQuerySetCmd>();
+                QuerySet* querySet = ToBackend(cmd->querySet.Get());
+                Buffer* destination = ToBackend(cmd->destination.Get());
+
+                size_t size = cmd->queryCount * sizeof(uint64_t);
+                destination->EnsureDataInitializedAsDestination(cmd->destinationOffset, size);
+
+                std::vector<uint64_t> values(cmd->queryCount);
+                auto availability = querySet->GetQueryAvailability();
+
+                for (uint32_t i = 0; i < cmd->queryCount; ++i) {
+                    if (!availability[cmd->firstQuery + i]) {
+                        values[i] = 0;
+                        continue;
+                    }
+                    uint32_t query = querySet->Get(cmd->firstQuery + i);
+                    GLuint value;
+                    gl.GetQueryObjectuiv(query, GL_QUERY_RESULT, &value);
+                    values[i] = value;
+                }
+
+                gl.BindBuffer(GL_ARRAY_BUFFER, destination->GetHandle());
+                gl.BufferSubData(GL_ARRAY_BUFFER, cmd->destinationOffset, size, values.data());
+
                 break;
             }
 
@@ -1317,11 +1340,16 @@
             }
 
             case Command::BeginOcclusionQuery: {
-                return DAWN_UNIMPLEMENTED_ERROR("BeginOcclusionQuery unimplemented.");
+                BeginOcclusionQueryCmd* cmd = mCommands.NextCommand<BeginOcclusionQueryCmd>();
+                QuerySet* querySet = ToBackend(renderPass->occlusionQuerySet.Get());
+                gl.BeginQuery(GL_ANY_SAMPLES_PASSED, querySet->Get(cmd->queryIndex));
+                break;
             }
 
             case Command::EndOcclusionQuery: {
-                return DAWN_UNIMPLEMENTED_ERROR("EndOcclusionQuery unimplemented.");
+                mCommands.NextCommand<EndOcclusionQueryCmd>();
+                gl.EndQuery(GL_ANY_SAMPLES_PASSED);
+                break;
             }
 
             case Command::WriteTimestamp:
diff --git a/src/dawn/native/opengl/QuerySetGL.cpp b/src/dawn/native/opengl/QuerySetGL.cpp
index 984e5f5..6907730 100644
--- a/src/dawn/native/opengl/QuerySetGL.cpp
+++ b/src/dawn/native/opengl/QuerySetGL.cpp
@@ -32,8 +32,25 @@
 namespace dawn::native::opengl {
 
 QuerySet::QuerySet(Device* device, const QuerySetDescriptor* descriptor)
-    : QuerySetBase(device, descriptor) {}
+    : QuerySetBase(device, descriptor), mQueries(descriptor->count) {
+    if (mQueries.size() > 0) {
+        const OpenGLFunctions& gl = device->GetGL();
+        gl.GenQueries(descriptor->count, mQueries.data());
+    }
+}
 
 QuerySet::~QuerySet() = default;
 
+void QuerySet::DestroyImpl() {
+    const OpenGLFunctions& gl = ToBackend(GetDevice())->GetGL();
+    if (mQueries.size() > 0) {
+        gl.DeleteQueries(mQueries.size(), mQueries.data());
+    }
+    QuerySetBase::DestroyImpl();
+}
+
+GLuint QuerySet::Get(uint32_t index) const {
+    return mQueries[index];
+}
+
 }  // namespace dawn::native::opengl
diff --git a/src/dawn/native/opengl/QuerySetGL.h b/src/dawn/native/opengl/QuerySetGL.h
index 78ef510..cea8e4b 100644
--- a/src/dawn/native/opengl/QuerySetGL.h
+++ b/src/dawn/native/opengl/QuerySetGL.h
@@ -28,7 +28,10 @@
 #ifndef SRC_DAWN_NATIVE_OPENGL_QUERYSETGL_H_
 #define SRC_DAWN_NATIVE_OPENGL_QUERYSETGL_H_
 
+#include <vector>
+
 #include "dawn/native/QuerySet.h"
+#include "dawn/native/opengl/opengl_platform.h"
 
 namespace dawn::native::opengl {
 
@@ -37,9 +40,12 @@
 class QuerySet final : public QuerySetBase {
   public:
     QuerySet(Device* device, const QuerySetDescriptor* descriptor);
+    GLuint Get(uint32_t index) const;
 
   private:
     ~QuerySet() override;
+    void DestroyImpl() override;
+    std::vector<GLuint> mQueries;
 };
 
 }  // namespace dawn::native::opengl
diff --git a/src/dawn/tests/end2end/QueryTests.cpp b/src/dawn/tests/end2end/QueryTests.cpp
index fed9bcc..dc86062 100644
--- a/src/dawn/tests/end2end/QueryTests.cpp
+++ b/src/dawn/tests/end2end/QueryTests.cpp
@@ -391,6 +391,9 @@
     // TODO(dawn:1870): D3D11_QUERY_OCCLUSION_PREDICATE doesn't work on Intel Gen12.
     DAWN_SUPPRESS_TEST_IF(IsD3D11() && IsIntelGen12());
 
+    // TODO(dawn:2247): Failing on ANGLE/D3D11
+    DAWN_SUPPRESS_TEST_IF(IsANGLED3D11());
+
     constexpr uint32_t kQueryCount = 1;
 
     wgpu::QuerySet querySet = CreateOcclusionQuerySet(kQueryCount);
@@ -475,6 +478,9 @@
     // TODO(dawn:1870): D3D11_QUERY_OCCLUSION_PREDICATE doesn't work on Intel Gen12.
     DAWN_SUPPRESS_TEST_IF(IsD3D11() && IsIntelGen12());
 
+    // TODO(dawn:2247): Failing on ANGLE/D3D11
+    DAWN_SUPPRESS_TEST_IF(IsANGLED3D11());
+
     constexpr uint32_t kQueryCount = 1;
 
     utils::ComboRenderPipelineDescriptor descriptor;
@@ -1291,6 +1297,8 @@
                       D3D12Backend(),
                       MetalBackend(),
                       MetalBackend({"metal_fill_empty_occlusion_queries_with_zero"}),
+                      OpenGLBackend(),
+                      OpenGLESBackend(),
                       VulkanBackend());
 DAWN_INSTANTIATE_TEST(TimestampQueryTests,
                       D3D11Backend(),