opengl: Implement blend state
diff --git a/src/backend/opengl/BlendStateGL.cpp b/src/backend/opengl/BlendStateGL.cpp
index a595ee1..bf90267 100644
--- a/src/backend/opengl/BlendStateGL.cpp
+++ b/src/backend/opengl/BlendStateGL.cpp
@@ -15,12 +15,90 @@
 #include "backend/opengl/BlendStateGL.h"
 
 #include "backend/opengl/OpenGLBackend.h"
+#include "common/Assert.h"
 
 namespace backend {
 namespace opengl {
 
+    namespace {
+        GLenum GLBlendFactor(nxt::BlendFactor factor, bool alpha) {
+            switch (factor) {
+                case nxt::BlendFactor::Zero:
+                    return GL_ZERO;
+                case nxt::BlendFactor::One:
+                    return GL_ONE;
+                case nxt::BlendFactor::SrcColor:
+                    return GL_SRC_COLOR;
+                case nxt::BlendFactor::OneMinusSrcColor:
+                    return GL_ONE_MINUS_SRC_COLOR;
+                case nxt::BlendFactor::SrcAlpha:
+                    return GL_SRC_ALPHA;
+                case nxt::BlendFactor::OneMinusSrcAlpha:
+                    return GL_ONE_MINUS_SRC_ALPHA;
+                case nxt::BlendFactor::DstColor:
+                    return GL_DST_COLOR;
+                case nxt::BlendFactor::OneMinusDstColor:
+                    return GL_ONE_MINUS_DST_COLOR;
+                case nxt::BlendFactor::DstAlpha:
+                    return GL_DST_ALPHA;
+                case nxt::BlendFactor::OneMinusDstAlpha:
+                    return GL_ONE_MINUS_DST_ALPHA;
+                case nxt::BlendFactor::SrcAlphaSaturated:
+                    return GL_SRC_ALPHA_SATURATE;
+                case nxt::BlendFactor::BlendColor:
+                    return alpha ? GL_CONSTANT_ALPHA : GL_CONSTANT_COLOR;
+                case nxt::BlendFactor::OneMinusBlendColor:
+                    return alpha ? GL_ONE_MINUS_CONSTANT_ALPHA : GL_ONE_MINUS_CONSTANT_COLOR;
+                case nxt::BlendFactor::Src1Color:
+                    return GL_SRC1_COLOR;
+                case nxt::BlendFactor::OneMinusSrc1Color:
+                    return GL_ONE_MINUS_SRC1_COLOR;
+                case nxt::BlendFactor::Src1Alpha:
+                    return GL_SRC1_ALPHA;
+                case nxt::BlendFactor::OneMinusSrc1Alpha:
+                    return GL_ONE_MINUS_SRC1_ALPHA;
+                default:
+                    UNREACHABLE();
+            }
+        }
+
+        GLenum GLBlendMode(nxt::BlendOperation operation) {
+            switch (operation) {
+                case nxt::BlendOperation::Add:
+                    return GL_FUNC_ADD;
+                case nxt::BlendOperation::Subtract:
+                    return GL_FUNC_SUBTRACT;
+                case nxt::BlendOperation::ReverseSubtract:
+                    return GL_FUNC_REVERSE_SUBTRACT;
+                case nxt::BlendOperation::Min:
+                    return GL_MIN;
+                case nxt::BlendOperation::Max:
+                    return GL_MAX;
+                default:
+                    UNREACHABLE();
+            }
+        }
+    }
+
     BlendState::BlendState(BlendStateBuilder* builder) : BlendStateBase(builder) {
     }
 
+    void BlendState::ApplyNow(uint32_t attachment) {
+        const auto& info = GetBlendInfo();
+
+        if (info.blendEnabled) {
+            glEnablei(GL_BLEND, attachment);
+            glBlendEquationSeparatei(attachment, GLBlendMode(info.colorBlend.operation), GLBlendMode(info.alphaBlend.operation));
+            glBlendFuncSeparatei(attachment, GLBlendFactor(info.colorBlend.srcFactor, false), GLBlendFactor(info.colorBlend.dstFactor, false), GLBlendFactor(info.alphaBlend.srcFactor, true), GLBlendFactor(info.alphaBlend.dstFactor, true));
+            glColorMaski(attachment,
+                info.colorWriteMask & nxt::ColorWriteMask::Red,
+                info.colorWriteMask & nxt::ColorWriteMask::Green,
+                info.colorWriteMask & nxt::ColorWriteMask::Blue,
+                info.colorWriteMask & nxt::ColorWriteMask::Alpha);
+        } else {
+            glDisablei(GL_BLEND, attachment);
+        }
+    }
+
 }
 }
diff --git a/src/backend/opengl/BlendStateGL.h b/src/backend/opengl/BlendStateGL.h
index aca960c..e286cd5 100644
--- a/src/backend/opengl/BlendStateGL.h
+++ b/src/backend/opengl/BlendStateGL.h
@@ -17,12 +17,16 @@
 
 #include "backend/BlendState.h"
 
+#include "glad/glad.h"
+
 namespace backend {
 namespace opengl {
 
     class BlendState : public BlendStateBase {
         public:
             BlendState(BlendStateBuilder* builder);
+
+            void ApplyNow(uint32_t attachment);
     };
 
 }
diff --git a/src/backend/opengl/CommandBufferGL.cpp b/src/backend/opengl/CommandBufferGL.cpp
index b3f91eb..5894266 100644
--- a/src/backend/opengl/CommandBufferGL.cpp
+++ b/src/backend/opengl/CommandBufferGL.cpp
@@ -338,7 +338,8 @@
 
                 case Command::SetBlendColor:
                     {
-                        commands.NextCommand<SetBlendColorCmd>();
+                        SetBlendColorCmd* cmd = commands.NextCommand<SetBlendColorCmd>();
+                        glBlendColor(cmd->r, cmd->g, cmd->b, cmd->a);
                     }
                     break;
 
diff --git a/src/backend/opengl/RenderPipelineGL.cpp b/src/backend/opengl/RenderPipelineGL.cpp
index cc83ed6..a5c2104 100644
--- a/src/backend/opengl/RenderPipelineGL.cpp
+++ b/src/backend/opengl/RenderPipelineGL.cpp
@@ -14,6 +14,7 @@
 
 #include "backend/opengl/RenderPipelineGL.h"
 
+#include "backend/opengl/BlendStateGL.h"
 #include "backend/opengl/DepthStencilStateGL.h"
 #include "backend/opengl/PersistentPipelineStateGL.h"
 #include "backend/opengl/OpenGLBackend.h"
@@ -57,6 +58,14 @@
 
         auto depthStencilState = ToBackend(GetDepthStencilState());
         depthStencilState->ApplyNow(persistentPipelineState);
+
+
+        RenderPass* renderPass = ToBackend(GetRenderPass());
+        auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
+
+        for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
+            ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
+        }
     }
 
 }