OpenGL: Don't use glad to load OpenGL entrypoints

This makes the OpenGL entry points loaded at Adapter creation from the
getProcAddress passed in the DiscoveryOptions and update all GL calls in
the backend to go through the new OpenGLFunctions object.

A code generator is added that generates the function loader and list of
GL procs from Khronos' gl.xml file but we can't get rid of glad yet
because it is used to have the PROC typedefs and enum values.

BUG=dawn:165

Change-Id: I2a583d79752f55877fa4190846f5be16cf91651a
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7983
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
This commit is contained in:
Corentin Wallez 2019-06-13 10:22:32 +00:00 committed by Commit Bot service account
parent 87ab2f96d9
commit df69f24824
22 changed files with 51252 additions and 286 deletions

View File

@ -44,6 +44,20 @@ dawn_json_generator("libdawn_native_utils_gen") {
] ]
} }
if (dawn_enable_opengl) {
dawn_generator("libdawn_native_opengl_loader_gen") {
script = "generator/opengl_loader_generator.py"
args = [
"--gl-xml",
rebase_path("third_party/gl.xml", root_build_dir),
]
outputs = [
"dawn_native/opengl/OpenGLFunctionsBase_autogen.cpp",
"dawn_native/opengl/OpenGLFunctionsBase_autogen.h",
]
}
}
# Public libdawn_native headers so they can be publically visible for # Public libdawn_native headers so they can be publically visible for
# dependencies of libdawn_native # dependencies of libdawn_native
source_set("libdawn_native_headers") { source_set("libdawn_native_headers") {
@ -261,7 +275,11 @@ source_set("libdawn_native_sources") {
} }
if (dawn_enable_opengl) { if (dawn_enable_opengl) {
deps += [ "third_party:glad" ] deps += [
":libdawn_native_opengl_loader_gen",
"third_party:glad",
]
sources += get_target_outputs(":libdawn_native_opengl_loader_gen")
sources += [ sources += [
"src/dawn_native/opengl/BackendGL.cpp", "src/dawn_native/opengl/BackendGL.cpp",
"src/dawn_native/opengl/BackendGL.h", "src/dawn_native/opengl/BackendGL.h",
@ -274,6 +292,8 @@ source_set("libdawn_native_sources") {
"src/dawn_native/opengl/DeviceGL.cpp", "src/dawn_native/opengl/DeviceGL.cpp",
"src/dawn_native/opengl/DeviceGL.h", "src/dawn_native/opengl/DeviceGL.h",
"src/dawn_native/opengl/Forward.h", "src/dawn_native/opengl/Forward.h",
"src/dawn_native/opengl/OpenGLFunctions.cpp",
"src/dawn_native/opengl/OpenGLFunctions.h",
"src/dawn_native/opengl/PersistentPipelineStateGL.cpp", "src/dawn_native/opengl/PersistentPipelineStateGL.cpp",
"src/dawn_native/opengl/PersistentPipelineStateGL.h", "src/dawn_native/opengl/PersistentPipelineStateGL.h",
"src/dawn_native/opengl/PipelineGL.cpp", "src/dawn_native/opengl/PipelineGL.cpp",

View File

@ -47,6 +47,11 @@ template("dawn_generator") {
generator_args += invoker.args generator_args += invoker.args
} }
generator_args += [
"--template-dir",
rebase_path("${dawn_root}/generator/templates", root_build_dir),
]
# Use the Jinja2 version pulled from the DEPS file. We do it so we don't # Use the Jinja2 version pulled from the DEPS file. We do it so we don't
# have version problems, and users don't have to install Jinja2. # have version problems, and users don't have to install Jinja2.
jinja2_python_path = rebase_path("${dawn_jinja2_dir}/..") jinja2_python_path = rebase_path("${dawn_jinja2_dir}/..")
@ -138,7 +143,6 @@ template("dawn_generator") {
# } # }
template("dawn_json_generator") { template("dawn_json_generator") {
dawn_generator(target_name) { dawn_generator(target_name) {
script = "${dawn_root}/generator/dawn_json_generator.py" script = "${dawn_root}/generator/dawn_json_generator.py"
# The base arguments for the generator: from this dawn.json, generate this # The base arguments for the generator: from this dawn.json, generate this
@ -148,8 +152,6 @@ template("dawn_json_generator") {
rebase_path("${dawn_root}/dawn.json", root_build_dir), rebase_path("${dawn_root}/dawn.json", root_build_dir),
"--wire-json", "--wire-json",
rebase_path("${dawn_root}/dawn_wire.json", root_build_dir), rebase_path("${dawn_root}/dawn_wire.json", root_build_dir),
"--template-dir",
rebase_path("${dawn_root}/generator/templates", root_build_dir),
"--targets", "--targets",
invoker.target, invoker.target,
] ]

View File

@ -44,7 +44,7 @@ import jinja2
# A custom Jinja2 template loader that removes the extra indentation # A custom Jinja2 template loader that removes the extra indentation
# of the template blocks so that the output is correctly indented # of the template blocks so that the output is correctly indented
class PreprocessingLoader(jinja2.BaseLoader): class _PreprocessingLoader(jinja2.BaseLoader):
def __init__(self, path): def __init__(self, path):
self.path = path self.path = path
@ -93,7 +93,7 @@ class PreprocessingLoader(jinja2.BaseLoader):
_FileOutput = namedtuple('FileOutput', ['name', 'content']) _FileOutput = namedtuple('FileOutput', ['name', 'content'])
def _do_renders(renders, template_dir): def _do_renders(renders, template_dir):
loader = PreprocessingLoader(template_dir) loader = _PreprocessingLoader(template_dir)
env = jinja2.Environment(loader=loader, lstrip_blocks=True, trim_blocks=True, line_comment_prefix='//*') env = jinja2.Environment(loader=loader, lstrip_blocks=True, trim_blocks=True, line_comment_prefix='//*')
def do_assert(expr): def do_assert(expr):

View File

@ -0,0 +1,117 @@
#!/usr/bin/env python2
# Copyright 2019 The Dawn Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os, sys
from collections import namedtuple
import xml.etree.ElementTree as etree
from generator_lib import Generator, run_generator, FileRender
class Proc:
def __init__(self, gl_name, proc_name=None):
assert(gl_name.startswith('gl'))
if proc_name == None:
proc_name = gl_name[2:]
self.gl_name = gl_name
self.proc_name = proc_name
def glProcName(self):
return self.gl_name
def ProcName(self):
return self.proc_name
def PFNPROCNAME(self):
return 'PFN' + self.gl_name.upper() + 'PROC'
def __repr__(self):
return 'Proc("{}", "{}")'.format(self.gl_name, self.proc_name)
Version = namedtuple('Version', ['major', 'minor'])
VersionProcBlock = namedtuple('ProcBlock', ['version', 'procs'])
HeaderProcBlock = namedtuple('ProcBlock', ['description', 'procs'])
def parse_version(version):
return Version(*map(int, version.split('.')))
def compute_params(root):
# Add proc blocks for OpenGL ES
gles_blocks = []
for gles_section in root.findall('''feature[@api='gles2']'''):
section_procs = []
for proc in gles_section.findall('./require/command'):
section_procs.append(Proc(proc.attrib['name']))
gles_blocks.append(VersionProcBlock(parse_version(gles_section.attrib['number']), section_procs))
# Get the list of all Desktop OpenGL function removed by the Core Profile.
core_removed_procs = set()
for removed_section in root.findall('feature/remove'):
assert(removed_section.attrib['profile'] == 'core')
for proc in removed_section.findall('./command'):
core_removed_procs.add(proc.attrib['name'])
# Add proc blocks for Desktop GL
desktop_gl_blocks = []
for gl_section in root.findall('''feature[@api='gl']'''):
section_procs = []
for proc in gl_section.findall('./require/command'):
if proc.attrib['name'] not in core_removed_procs:
section_procs.append(Proc(proc.attrib['name']))
desktop_gl_blocks.append(VersionProcBlock(parse_version(gl_section.attrib['number']), section_procs))
already_added_header_procs = set()
header_blocks = []
def add_header_block(description, procs):
block_procs = []
for proc in procs:
if not proc.glProcName() in already_added_header_procs:
already_added_header_procs.add(proc.glProcName())
block_procs.append(proc)
if len(block_procs) > 0:
header_blocks.append(HeaderProcBlock(description, block_procs))
for block in gles_blocks:
add_header_block('OpenGL ES {}.{}'.format(block.version.major, block.version.minor), block.procs)
for block in desktop_gl_blocks:
add_header_block('Desktop OpenGL {}.{}'.format(block.version.major, block.version.minor), block.procs)
return {
'gles_blocks': gles_blocks,
'desktop_gl_blocks': desktop_gl_blocks,
'header_blocks': header_blocks,
}
class OpenGLLoaderGenerator(Generator):
def get_description(self):
return 'Generates code to load OpenGL function pointers'
def add_commandline_arguments(self, parser):
parser.add_argument('--gl-xml', required=True, type=str, help ='The Khronos gl.xml to use.')
def get_file_renders(self, args):
params = compute_params(etree.parse(args.gl_xml).getroot())
return [
FileRender('opengl/OpenGLFunctionsBase.cpp', 'dawn_native/opengl/OpenGLFunctionsBase_autogen.cpp', [params]),
FileRender('opengl/OpenGLFunctionsBase.h', 'dawn_native/opengl/OpenGLFunctionsBase_autogen.h', [params]),
]
def get_dependencies(self, args):
return [os.path.abspath(args.gl_xml)]
if __name__ == '__main__':
sys.exit(run_generator(OpenGLLoaderGenerator()))

View File

@ -0,0 +1,54 @@
//* Copyright 2019 The Dawn Authors
//*
//* Licensed under the Apache License, Version 2.0 (the "License");
//* you may not use this file except in compliance with the License.
//* You may obtain a copy of the License at
//*
//* http://www.apache.org/licenses/LICENSE-2.0
//*
//* Unless required by applicable law or agreed to in writing, software
//* distributed under the License is distributed on an "AS IS" BASIS,
//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//* See the License for the specific language governing permissions and
//* limitations under the License.
#include "dawn_native/opengl/OpenGLFunctionsBase_autogen.h"
namespace dawn_native { namespace opengl {
template<typename T>
MaybeError OpenGLFunctionsBase::LoadProc(GetProcAddress getProc, T* memberProc, const char* name) {
*memberProc = reinterpret_cast<T>(getProc(name));
if (DAWN_UNLIKELY(memberProc == nullptr)) {
return DAWN_CONTEXT_LOST_ERROR(std::string("Couldn't load GL proc: ") + name);
}
return {};
}
MaybeError OpenGLFunctionsBase::LoadOpenGLESProcs(GetProcAddress getProc, int majorVersion, int minorVersion) {
{% for block in gles_blocks %}
// OpenGL ES {{block.version.major}}.{{block.version.minor}}
if (majorVersion > {{block.version.major}} || (majorVersion == {{block.version.major}} && minorVersion >= {{block.version.minor}})) {
{% for proc in block.procs %}
DAWN_TRY(LoadProc(getProc, &{{proc.ProcName()}}, "{{proc.glProcName()}}"));
{% endfor %}
}
{% endfor %}
return {};
}
MaybeError OpenGLFunctionsBase::LoadDesktopGLProcs(GetProcAddress getProc, int majorVersion, int minorVersion) {
{% for block in desktop_gl_blocks %}
// Desktop OpenGL {{block.version.major}}.{{block.version.minor}}
if (majorVersion > {{block.version.major}} || (majorVersion == {{block.version.major}} && minorVersion >= {{block.version.minor}})) {
{% for proc in block.procs %}
DAWN_TRY(LoadProc(getProc, &{{proc.ProcName()}}, "{{proc.glProcName()}}"));
{% endfor %}
}
{% endfor %}
return {};
}
}} // namespace dawn_native::opengl

View File

@ -0,0 +1,41 @@
//* Copyright 2019 The Dawn Authors
//*
//* Licensed under the Apache License, Version 2.0 (the "License");
//* you may not use this file except in compliance with the License.
//* You may obtain a copy of the License at
//*
//* http://www.apache.org/licenses/LICENSE-2.0
//*
//* Unless required by applicable law or agreed to in writing, software
//* distributed under the License is distributed on an "AS IS" BASIS,
//* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//* See the License for the specific language governing permissions and
//* limitations under the License.
#include "dawn_native/Error.h"
#include <glad/glad.h>
namespace dawn_native { namespace opengl {
using GetProcAddress = void* (*) (const char*);
struct OpenGLFunctionsBase {
public:
{% for block in header_blocks %}
// {{block.description}}
{% for proc in block.procs %}
{{proc.PFNPROCNAME()}} {{proc.ProcName()}} = nullptr;
{% endfor %}
{% endfor%}
protected:
MaybeError LoadDesktopGLProcs(GetProcAddress getProc, int majorVersion, int minorVersion);
MaybeError LoadOpenGLESProcs(GetProcAddress getProc, int majorVersion, int minorVersion);
private:
template<typename T>
MaybeError LoadProc(GetProcAddress getProc, T* memberProc, const char* name);
};
}} // namespace dawn_native::opengl

View File

@ -23,26 +23,33 @@ namespace dawn_native { namespace opengl {
class Adapter : public AdapterBase { class Adapter : public AdapterBase {
public: public:
Adapter(InstanceBase* instance, const AdapterDiscoveryOptions* options) Adapter(InstanceBase* instance) : AdapterBase(instance, BackendType::OpenGL) {
: AdapterBase(instance, BackendType::OpenGL) { }
// Use getProc to populate GLAD.
gladLoadGLLoader(reinterpret_cast<GLADloadproc>(options->getProc)); MaybeError Initialize(const AdapterDiscoveryOptions* options) {
// Use getProc to populate the dispatch table
DAWN_TRY(mFunctions.Initialize(options->getProc));
// Set state that never changes between devices. // Set state that never changes between devices.
glEnable(GL_DEPTH_TEST); mFunctions.Enable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST); mFunctions.Enable(GL_SCISSOR_TEST);
glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); mFunctions.Enable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
glEnable(GL_MULTISAMPLE); mFunctions.Enable(GL_MULTISAMPLE);
mPCIInfo.name = reinterpret_cast<const char*>(glGetString(GL_RENDERER)); mPCIInfo.name = reinterpret_cast<const char*>(mFunctions.GetString(GL_RENDERER));
return {};
} }
virtual ~Adapter() = default;
~Adapter() override = default;
private: private:
OpenGLFunctions mFunctions;
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override { ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
// There is no limit on the number of devices created from this adapter because they can // There is no limit on the number of devices created from this adapter because they can
// all share the same backing OpenGL context. // all share the same backing OpenGL context.
return {new Device(this, descriptor)}; return {new Device(this, descriptor, mFunctions)};
} }
}; };
@ -58,9 +65,8 @@ namespace dawn_native { namespace opengl {
ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters( ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
const AdapterDiscoveryOptionsBase* optionsBase) { const AdapterDiscoveryOptionsBase* optionsBase) {
// TODO(cwallez@chromium.org): For now we can only create a single adapter because glad uses // TODO(cwallez@chromium.org): For now only create a single OpenGL adapter because don't
// static variables to store the pointers to OpenGL procs. Also, if we could create // know how to handle MakeCurrent.
// multiple adapters, we would need to figure out what to do about MakeCurrent.
if (mCreatedAdapter) { if (mCreatedAdapter) {
return DAWN_VALIDATION_ERROR("The OpenGL backend can only create a single adapter"); return DAWN_VALIDATION_ERROR("The OpenGL backend can only create a single adapter");
} }
@ -73,10 +79,12 @@ namespace dawn_native { namespace opengl {
return DAWN_VALIDATION_ERROR("AdapterDiscoveryOptions::getProc must be set"); return DAWN_VALIDATION_ERROR("AdapterDiscoveryOptions::getProc must be set");
} }
std::vector<std::unique_ptr<AdapterBase>> adapters; std::unique_ptr<Adapter> adapter = std::make_unique<Adapter>(GetInstance());
adapters.push_back(std::make_unique<Adapter>(GetInstance(), options)); DAWN_TRY(adapter->Initialize(options));
mCreatedAdapter = true; mCreatedAdapter = true;
std::vector<std::unique_ptr<AdapterBase>> adapters;
adapters.push_back(std::unique_ptr<AdapterBase>(adapter.release()));
return std::move(adapters); return std::move(adapters);
} }

View File

@ -22,9 +22,9 @@ namespace dawn_native { namespace opengl {
Buffer::Buffer(Device* device, const BufferDescriptor* descriptor) Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
: BufferBase(device, descriptor) { : BufferBase(device, descriptor) {
glGenBuffers(1, &mBuffer); device->gl.GenBuffers(1, &mBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
glBufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW); device->gl.BufferData(GL_ARRAY_BUFFER, GetSize(), nullptr, GL_STATIC_DRAW);
} }
Buffer::~Buffer() { Buffer::~Buffer() {
@ -42,41 +42,51 @@ namespace dawn_native { namespace opengl {
} }
MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) { MaybeError Buffer::MapAtCreationImpl(uint8_t** mappedPointer) {
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* data = gl.MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
*mappedPointer = reinterpret_cast<uint8_t*>(data); *mappedPointer = reinterpret_cast<uint8_t*>(data);
return {}; return {};
} }
MaybeError Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const void* data) { MaybeError Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const void* data) {
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
glBufferSubData(GL_ARRAY_BUFFER, start, count, data);
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
gl.BufferSubData(GL_ARRAY_BUFFER, start, count, data);
return {}; return {};
} }
void Buffer::MapReadAsyncImpl(uint32_t serial) { void Buffer::MapReadAsyncImpl(uint32_t serial) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
// TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high // TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high
// version of OpenGL that would let us map the buffer unsynchronized. // version of OpenGL that would let us map the buffer unsynchronized.
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY); void* data = gl.MapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
CallMapReadCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, GetSize()); CallMapReadCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, GetSize());
} }
void Buffer::MapWriteAsyncImpl(uint32_t serial) { void Buffer::MapWriteAsyncImpl(uint32_t serial) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
// TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high // TODO(cwallez@chromium.org): this does GPU->CPU synchronization, we could require a high
// version of OpenGL that would let us map the buffer unsynchronized. // version of OpenGL that would let us map the buffer unsynchronized.
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
void* data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); void* data = gl.MapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
CallMapWriteCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, GetSize()); CallMapWriteCallback(serial, DAWN_BUFFER_MAP_ASYNC_STATUS_SUCCESS, data, GetSize());
} }
void Buffer::UnmapImpl() { void Buffer::UnmapImpl() {
glBindBuffer(GL_ARRAY_BUFFER, mBuffer); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
glUnmapBuffer(GL_ARRAY_BUFFER);
gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
gl.UnmapBuffer(GL_ARRAY_BUFFER);
} }
void Buffer::DestroyImpl() { void Buffer::DestroyImpl() {
glDeleteBuffers(1, &mBuffer); ToBackend(GetDevice())->gl.DeleteBuffers(1, &mBuffer);
mBuffer = 0; mBuffer = 0;
} }

View File

@ -174,9 +174,9 @@ namespace dawn_native { namespace opengl {
mLastPipeline = pipeline; mLastPipeline = pipeline;
} }
void Apply() { void Apply(const OpenGLFunctions& gl) {
if (mIndexBufferDirty && mIndexBuffer != nullptr) { if (mIndexBufferDirty && mIndexBuffer != nullptr) {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetHandle()); gl.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndexBuffer->GetHandle());
mIndexBufferDirty = false; mIndexBufferDirty = false;
} }
@ -194,13 +194,13 @@ namespace dawn_native { namespace opengl {
auto formatType = VertexFormatType(attribute.format); auto formatType = VertexFormatType(attribute.format);
GLboolean normalized = VertexFormatIsNormalized(attribute.format); GLboolean normalized = VertexFormatIsNormalized(attribute.format);
glBindBuffer(GL_ARRAY_BUFFER, buffer); gl.BindBuffer(GL_ARRAY_BUFFER, buffer);
if (VertexFormatIsInt(attribute.format)) { if (VertexFormatIsInt(attribute.format)) {
glVertexAttribIPointer(location, components, formatType, input.stride, gl.VertexAttribIPointer(location, components, formatType, input.stride,
reinterpret_cast<void*>(static_cast<intptr_t>( reinterpret_cast<void*>(static_cast<intptr_t>(
offset + attribute.offset))); offset + attribute.offset)));
} else { } else {
glVertexAttribPointer( gl.VertexAttribPointer(
location, components, formatType, normalized, input.stride, location, components, formatType, normalized, input.stride,
reinterpret_cast<void*>( reinterpret_cast<void*>(
static_cast<intptr_t>(offset + attribute.offset))); static_cast<intptr_t>(offset + attribute.offset)));
@ -224,7 +224,8 @@ namespace dawn_native { namespace opengl {
// Handles SetBindGroup commands with the specifics of translating to OpenGL texture and // Handles SetBindGroup commands with the specifics of translating to OpenGL texture and
// buffer units // buffer units
void ApplyBindGroup(uint32_t index, void ApplyBindGroup(const OpenGLFunctions& gl,
uint32_t index,
BindGroupBase* group, BindGroupBase* group,
PipelineLayout* pipelineLayout, PipelineLayout* pipelineLayout,
PipelineGL* pipeline) { PipelineGL* pipeline) {
@ -238,7 +239,7 @@ namespace dawn_native { namespace opengl {
GLuint buffer = ToBackend(binding.buffer)->GetHandle(); GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint uboIndex = indices[bindingIndex]; GLuint uboIndex = indices[bindingIndex];
glBindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, binding.offset, gl.BindBufferRange(GL_UNIFORM_BUFFER, uboIndex, buffer, binding.offset,
binding.size); binding.size);
} break; } break;
@ -248,7 +249,7 @@ namespace dawn_native { namespace opengl {
GLuint samplerIndex = indices[bindingIndex]; GLuint samplerIndex = indices[bindingIndex];
for (auto unit : pipeline->GetTextureUnitsForSampler(samplerIndex)) { for (auto unit : pipeline->GetTextureUnitsForSampler(samplerIndex)) {
glBindSampler(unit, sampler); gl.BindSampler(unit, sampler);
} }
} break; } break;
@ -259,8 +260,8 @@ namespace dawn_native { namespace opengl {
GLuint viewIndex = indices[bindingIndex]; GLuint viewIndex = indices[bindingIndex];
for (auto unit : pipeline->GetTextureUnitsForTextureView(viewIndex)) { for (auto unit : pipeline->GetTextureUnitsForTextureView(viewIndex)) {
glActiveTexture(GL_TEXTURE0 + unit); gl.ActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(target, handle); gl.BindTexture(target, handle);
} }
} break; } break;
@ -269,7 +270,7 @@ namespace dawn_native { namespace opengl {
GLuint buffer = ToBackend(binding.buffer)->GetHandle(); GLuint buffer = ToBackend(binding.buffer)->GetHandle();
GLuint ssboIndex = indices[bindingIndex]; GLuint ssboIndex = indices[bindingIndex];
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer, gl.BindBufferRange(GL_SHADER_STORAGE_BUFFER, ssboIndex, buffer,
binding.offset, binding.size); binding.offset, binding.size);
} break; } break;
@ -282,7 +283,8 @@ namespace dawn_native { namespace opengl {
} }
} }
void ResolveMultisampledRenderTargets(const BeginRenderPassCmd* renderPass) { void ResolveMultisampledRenderTargets(const OpenGLFunctions& gl,
const BeginRenderPassCmd* renderPass) {
ASSERT(renderPass != nullptr); ASSERT(renderPass != nullptr);
GLuint readFbo = 0; GLuint readFbo = 0;
@ -292,8 +294,8 @@ namespace dawn_native { namespace opengl {
if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) { if (renderPass->colorAttachments[i].resolveTarget.Get() != nullptr) {
if (readFbo == 0) { if (readFbo == 0) {
ASSERT(writeFbo == 0); ASSERT(writeFbo == 0);
glGenFramebuffers(1, &readFbo); gl.GenFramebuffers(1, &readFbo);
glGenFramebuffers(1, &writeFbo); gl.GenFramebuffers(1, &writeFbo);
} }
const TextureBase* colorTexture = const TextureBase* colorTexture =
@ -303,8 +305,8 @@ namespace dawn_native { namespace opengl {
ASSERT(renderPass->colorAttachments[i].view->GetBaseMipLevel() == 0); ASSERT(renderPass->colorAttachments[i].view->GetBaseMipLevel() == 0);
GLuint colorHandle = ToBackend(colorTexture)->GetHandle(); GLuint colorHandle = ToBackend(colorTexture)->GetHandle();
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFbo); gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFbo);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
ToBackend(colorTexture)->GetGLTarget(), colorHandle, 0); ToBackend(colorTexture)->GetGLTarget(), colorHandle, 0);
const TextureBase* resolveTexture = const TextureBase* resolveTexture =
@ -312,27 +314,27 @@ namespace dawn_native { namespace opengl {
GLuint resolveTextureHandle = ToBackend(resolveTexture)->GetHandle(); GLuint resolveTextureHandle = ToBackend(resolveTexture)->GetHandle();
GLuint resolveTargetMipmapLevel = GLuint resolveTargetMipmapLevel =
renderPass->colorAttachments[i].resolveTarget->GetBaseMipLevel(); renderPass->colorAttachments[i].resolveTarget->GetBaseMipLevel();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, writeFbo); gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, writeFbo);
if (resolveTexture->GetArrayLayers() == 1) { if (resolveTexture->GetArrayLayers() == 1) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, resolveTextureHandle, GL_TEXTURE_2D, resolveTextureHandle,
resolveTargetMipmapLevel); resolveTargetMipmapLevel);
} else { } else {
GLuint resolveTargetArrayLayer = GLuint resolveTargetArrayLayer =
renderPass->colorAttachments[i].resolveTarget->GetBaseArrayLayer(); renderPass->colorAttachments[i].resolveTarget->GetBaseArrayLayer();
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
resolveTextureHandle, resolveTargetMipmapLevel, resolveTextureHandle, resolveTargetMipmapLevel,
resolveTargetArrayLayer); resolveTargetArrayLayer);
} }
glBlitFramebuffer(0, 0, renderPass->width, renderPass->height, 0, 0, gl.BlitFramebuffer(0, 0, renderPass->width, renderPass->height, 0, 0,
renderPass->width, renderPass->height, GL_COLOR_BUFFER_BIT, renderPass->width, renderPass->height, GL_COLOR_BUFFER_BIT,
GL_NEAREST); GL_NEAREST);
} }
} }
glDeleteFramebuffers(1, &readFbo); gl.DeleteFramebuffers(1, &readFbo);
glDeleteFramebuffers(1, &writeFbo); gl.DeleteFramebuffers(1, &writeFbo);
} }
} // namespace } // namespace
@ -345,6 +347,8 @@ namespace dawn_native { namespace opengl {
} }
void CommandBuffer::Execute() { void CommandBuffer::Execute() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
Command type; Command type;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
switch (type) { switch (type) {
@ -361,13 +365,14 @@ namespace dawn_native { namespace opengl {
case Command::CopyBufferToBuffer: { case Command::CopyBufferToBuffer: {
CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>(); CopyBufferToBufferCmd* copy = mCommands.NextCommand<CopyBufferToBufferCmd>();
glBindBuffer(GL_PIXEL_PACK_BUFFER, ToBackend(copy->source)->GetHandle()); gl.BindBuffer(GL_PIXEL_PACK_BUFFER, ToBackend(copy->source)->GetHandle());
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, ToBackend(copy->destination)->GetHandle()); gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER,
glCopyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER, ToBackend(copy->destination)->GetHandle());
gl.CopyBufferSubData(GL_PIXEL_PACK_BUFFER, GL_PIXEL_UNPACK_BUFFER,
copy->sourceOffset, copy->destinationOffset, copy->size); copy->sourceOffset, copy->destinationOffset, copy->size);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} break; } break;
case Command::CopyBufferToTexture: { case Command::CopyBufferToTexture: {
@ -380,22 +385,22 @@ namespace dawn_native { namespace opengl {
GLenum target = texture->GetGLTarget(); GLenum target = texture->GetGLTarget();
auto format = texture->GetGLFormat(); auto format = texture->GetGLFormat();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle()); gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer->GetHandle());
glActiveTexture(GL_TEXTURE0); gl.ActiveTexture(GL_TEXTURE0);
glBindTexture(target, texture->GetHandle()); gl.BindTexture(target, texture->GetHandle());
glPixelStorei(GL_UNPACK_ROW_LENGTH, gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
src.rowPitch / TextureFormatPixelSize(texture->GetFormat())); src.rowPitch / TextureFormatPixelSize(texture->GetFormat()));
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.imageHeight); gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, src.imageHeight);
switch (texture->GetDimension()) { switch (texture->GetDimension()) {
case dawn::TextureDimension::e2D: case dawn::TextureDimension::e2D:
if (texture->GetArrayLayers() > 1) { if (texture->GetArrayLayers() > 1) {
glTexSubImage3D( gl.TexSubImage3D(
target, dst.level, dst.origin.x, dst.origin.y, dst.slice, target, dst.level, dst.origin.x, dst.origin.y, dst.slice,
copySize.width, copySize.height, 1, format.format, format.type, copySize.width, copySize.height, 1, format.format, format.type,
reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
} else { } else {
glTexSubImage2D( gl.TexSubImage2D(
target, dst.level, dst.origin.x, dst.origin.y, copySize.width, target, dst.level, dst.origin.x, dst.origin.y, copySize.width,
copySize.height, format.format, format.type, copySize.height, format.format, format.type,
reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset))); reinterpret_cast<void*>(static_cast<uintptr_t>(src.offset)));
@ -405,10 +410,10 @@ namespace dawn_native { namespace opengl {
default: default:
UNREACHABLE(); UNREACHABLE();
} }
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0); gl.PixelStorei(GL_UNPACK_IMAGE_HEIGHT, 0);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
} break; } break;
case Command::CopyTextureToBuffer: { case Command::CopyTextureToBuffer: {
@ -423,19 +428,19 @@ namespace dawn_native { namespace opengl {
// The only way to move data from a texture to a buffer in GL is via // The only way to move data from a texture to a buffer in GL is via
// glReadPixels with a pack buffer. Create a temporary FBO for the copy. // glReadPixels with a pack buffer. Create a temporary FBO for the copy.
glBindTexture(target, texture->GetHandle()); gl.BindTexture(target, texture->GetHandle());
GLuint readFBO = 0; GLuint readFBO = 0;
glGenFramebuffers(1, &readFBO); gl.GenFramebuffers(1, &readFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, readFBO); gl.BindFramebuffer(GL_READ_FRAMEBUFFER, readFBO);
switch (texture->GetDimension()) { switch (texture->GetDimension()) {
case dawn::TextureDimension::e2D: case dawn::TextureDimension::e2D:
if (texture->GetArrayLayers() > 1) { if (texture->GetArrayLayers() > 1) {
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.FramebufferTextureLayer(
texture->GetHandle(), src.level, GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture->GetHandle(),
src.slice); src.level, src.slice);
} else { } else {
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gl.FramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture->GetHandle(), GL_TEXTURE_2D, texture->GetHandle(),
src.level); src.level);
} }
@ -445,19 +450,19 @@ namespace dawn_native { namespace opengl {
UNREACHABLE(); UNREACHABLE();
} }
glBindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle()); gl.BindBuffer(GL_PIXEL_PACK_BUFFER, buffer->GetHandle());
glPixelStorei(GL_PACK_ROW_LENGTH, gl.PixelStorei(GL_PACK_ROW_LENGTH,
dst.rowPitch / TextureFormatPixelSize(texture->GetFormat())); dst.rowPitch / TextureFormatPixelSize(texture->GetFormat()));
glPixelStorei(GL_PACK_IMAGE_HEIGHT, dst.imageHeight); gl.PixelStorei(GL_PACK_IMAGE_HEIGHT, dst.imageHeight);
ASSERT(copySize.depth == 1 && src.origin.z == 0); ASSERT(copySize.depth == 1 && src.origin.z == 0);
void* offset = reinterpret_cast<void*>(static_cast<uintptr_t>(dst.offset)); void* offset = reinterpret_cast<void*>(static_cast<uintptr_t>(dst.offset));
glReadPixels(src.origin.x, src.origin.y, copySize.width, copySize.height, gl.ReadPixels(src.origin.x, src.origin.y, copySize.width, copySize.height,
format.format, format.type, offset); format.format, format.type, offset);
glPixelStorei(GL_PACK_ROW_LENGTH, 0); gl.PixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); gl.PixelStorei(GL_PACK_IMAGE_HEIGHT, 0);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); gl.BindBuffer(GL_PIXEL_PACK_BUFFER, 0);
glDeleteFramebuffers(1, &readFBO); gl.DeleteFramebuffers(1, &readFBO);
} break; } break;
case Command::CopyTextureToTexture: { case Command::CopyTextureToTexture: {
@ -469,7 +474,7 @@ namespace dawn_native { namespace opengl {
Texture* srcTexture = ToBackend(src.texture.Get()); Texture* srcTexture = ToBackend(src.texture.Get());
Texture* dstTexture = ToBackend(dst.texture.Get()); Texture* dstTexture = ToBackend(dst.texture.Get());
glCopyImageSubData(srcTexture->GetHandle(), srcTexture->GetGLTarget(), gl.CopyImageSubData(srcTexture->GetHandle(), srcTexture->GetGLTarget(),
src.level, src.origin.x, src.origin.y, src.slice, src.level, src.origin.x, src.origin.y, src.slice,
dstTexture->GetHandle(), dstTexture->GetGLTarget(), dstTexture->GetHandle(), dstTexture->GetGLTarget(),
dst.level, dst.origin.x, dst.origin.y, dst.slice, dst.level, dst.origin.x, dst.origin.y, dst.slice,
@ -482,6 +487,7 @@ namespace dawn_native { namespace opengl {
} }
void CommandBuffer::ExecuteComputePass() { void CommandBuffer::ExecuteComputePass() {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
ComputePipeline* lastPipeline = nullptr; ComputePipeline* lastPipeline = nullptr;
Command type; Command type;
@ -494,9 +500,9 @@ namespace dawn_native { namespace opengl {
case Command::Dispatch: { case Command::Dispatch: {
DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>(); DispatchCmd* dispatch = mCommands.NextCommand<DispatchCmd>();
glDispatchCompute(dispatch->x, dispatch->y, dispatch->z); gl.DispatchCompute(dispatch->x, dispatch->y, dispatch->z);
// TODO(cwallez@chromium.org): add barriers to the API // TODO(cwallez@chromium.org): add barriers to the API
glMemoryBarrier(GL_ALL_BARRIER_BITS); gl.MemoryBarrier(GL_ALL_BARRIER_BITS);
} break; } break;
case Command::DispatchIndirect: { case Command::DispatchIndirect: {
@ -505,10 +511,10 @@ namespace dawn_native { namespace opengl {
uint64_t indirectBufferOffset = dispatch->indirectOffset; uint64_t indirectBufferOffset = dispatch->indirectOffset;
Buffer* indirectBuffer = ToBackend(dispatch->indirectBuffer.Get()); Buffer* indirectBuffer = ToBackend(dispatch->indirectBuffer.Get());
glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirectBuffer->GetHandle()); gl.BindBuffer(GL_DISPATCH_INDIRECT_BUFFER, indirectBuffer->GetHandle());
glDispatchComputeIndirect(static_cast<GLintptr>(indirectBufferOffset)); gl.DispatchComputeIndirect(static_cast<GLintptr>(indirectBufferOffset));
// TODO(cwallez@chromium.org): add barriers to the API // TODO(cwallez@chromium.org): add barriers to the API
glMemoryBarrier(GL_ALL_BARRIER_BITS); gl.MemoryBarrier(GL_ALL_BARRIER_BITS);
} break; } break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {
@ -519,7 +525,7 @@ namespace dawn_native { namespace opengl {
case Command::SetBindGroup: { case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
ApplyBindGroup(cmd->index, cmd->group.Get(), ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline); ToBackend(lastPipeline->GetLayout()), lastPipeline);
} break; } break;
@ -532,6 +538,7 @@ namespace dawn_native { namespace opengl {
} }
void CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass) { void CommandBuffer::ExecuteRenderPass(BeginRenderPassCmd* renderPass) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
GLuint fbo = 0; GLuint fbo = 0;
// Create the framebuffer used for this render pass and calls the correct glDrawBuffers // Create the framebuffer used for this render pass and calls the correct glDrawBuffers
@ -540,12 +547,12 @@ namespace dawn_native { namespace opengl {
// Windows/Intel. It should break any feedback loop before the clears, even if there // Windows/Intel. It should break any feedback loop before the clears, even if there
// shouldn't be any negative effects from this. Investigate whether it's actually // shouldn't be any negative effects from this. Investigate whether it's actually
// needed. // needed.
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); gl.BindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// TODO(kainino@chromium.org): possible future optimization: create these framebuffers // TODO(kainino@chromium.org): possible future optimization: create these framebuffers
// at Framebuffer build time (or maybe CommandBuffer build time) so they don't have to // at Framebuffer build time (or maybe CommandBuffer build time) so they don't have to
// be created and destroyed at draw time. // be created and destroyed at draw time.
glGenFramebuffers(1, &fbo); gl.GenFramebuffers(1, &fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); gl.BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
// Mapping from attachmentSlot to GL framebuffer attachment points. Defaults to zero // Mapping from attachmentSlot to GL framebuffer attachment points. Defaults to zero
// (GL_NONE). // (GL_NONE).
@ -561,10 +568,10 @@ namespace dawn_native { namespace opengl {
// Attach color buffers. // Attach color buffers.
if (textureView->GetTexture()->GetArrayLayers() == 1) { if (textureView->GetTexture()->GetArrayLayers() == 1) {
GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget(); GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target, gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, target,
texture, textureView->GetBaseMipLevel()); texture, textureView->GetBaseMipLevel());
} else { } else {
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, gl.FramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
texture, textureView->GetBaseMipLevel(), texture, textureView->GetBaseMipLevel(),
textureView->GetBaseArrayLayer()); textureView->GetBaseArrayLayer());
} }
@ -579,7 +586,7 @@ namespace dawn_native { namespace opengl {
format == dawn::TextureFormat::R8Unorm || format == dawn::TextureFormat::R8Unorm ||
format == dawn::TextureFormat::B8G8R8A8Unorm); format == dawn::TextureFormat::B8G8R8A8Unorm);
} }
glDrawBuffers(attachmentCount, drawBuffers.data()); gl.DrawBuffers(attachmentCount, drawBuffers.data());
if (renderPass->hasDepthStencilAttachment) { if (renderPass->hasDepthStencilAttachment) {
TextureViewBase* textureView = renderPass->depthStencilAttachment.view.Get(); TextureViewBase* textureView = renderPass->depthStencilAttachment.view.Get();
@ -601,7 +608,7 @@ namespace dawn_native { namespace opengl {
} }
GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget(); GLenum target = ToBackend(textureView->GetTexture())->GetGLTarget();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, target, texture, 0); gl.FramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, target, texture, 0);
// TODO(kainino@chromium.org): the depth/stencil clears (later in // TODO(kainino@chromium.org): the depth/stencil clears (later in
// this function) may be undefined for other texture formats. // this function) may be undefined for other texture formats.
@ -611,10 +618,10 @@ namespace dawn_native { namespace opengl {
// Set defaults for dynamic state before executing clears and commands. // Set defaults for dynamic state before executing clears and commands.
PersistentPipelineState persistentPipelineState; PersistentPipelineState persistentPipelineState;
persistentPipelineState.SetDefaultState(); persistentPipelineState.SetDefaultState(gl);
glBlendColor(0, 0, 0, 0); gl.BlendColor(0, 0, 0, 0);
glViewport(0, 0, renderPass->width, renderPass->height); gl.Viewport(0, 0, renderPass->width, renderPass->height);
glScissor(0, 0, renderPass->width, renderPass->height); gl.Scissor(0, 0, renderPass->width, renderPass->height);
// Clear framebuffer attachments as needed // Clear framebuffer attachments as needed
{ {
@ -623,8 +630,8 @@ namespace dawn_native { namespace opengl {
// Load op - color // Load op - color
if (attachmentInfo.loadOp == dawn::LoadOp::Clear) { if (attachmentInfo.loadOp == dawn::LoadOp::Clear) {
glColorMaski(i, true, true, true, true); gl.ColorMaski(i, true, true, true, true);
glClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r); gl.ClearBufferfv(GL_COLOR, i, &attachmentInfo.clearColor.r);
} }
} }
@ -640,20 +647,20 @@ namespace dawn_native { namespace opengl {
(attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear); (attachmentInfo.stencilLoadOp == dawn::LoadOp::Clear);
if (doDepthClear) { if (doDepthClear) {
glDepthMask(GL_TRUE); gl.DepthMask(GL_TRUE);
} }
if (doStencilClear) { if (doStencilClear) {
glStencilMask(GetStencilMaskFromStencilFormat(attachmentFormat)); gl.StencilMask(GetStencilMaskFromStencilFormat(attachmentFormat));
} }
if (doDepthClear && doStencilClear) { if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth, gl.ClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
attachmentInfo.clearStencil); attachmentInfo.clearStencil);
} else if (doDepthClear) { } else if (doDepthClear) {
glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth); gl.ClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
} else if (doStencilClear) { } else if (doStencilClear) {
const GLint clearStencil = attachmentInfo.clearStencil; const GLint clearStencil = attachmentInfo.clearStencil;
glClearBufferiv(GL_STENCIL, 0, &clearStencil); gl.ClearBufferiv(GL_STENCIL, 0, &clearStencil);
} }
} }
} }
@ -670,24 +677,24 @@ namespace dawn_native { namespace opengl {
mCommands.NextCommand<EndRenderPassCmd>(); mCommands.NextCommand<EndRenderPassCmd>();
if (renderPass->sampleCount > 1) { if (renderPass->sampleCount > 1) {
ResolveMultisampledRenderTargets(renderPass); ResolveMultisampledRenderTargets(gl, renderPass);
} }
glDeleteFramebuffers(1, &fbo); gl.DeleteFramebuffers(1, &fbo);
return; return;
} break; } break;
case Command::Draw: { case Command::Draw: {
DrawCmd* draw = mCommands.NextCommand<DrawCmd>(); DrawCmd* draw = mCommands.NextCommand<DrawCmd>();
inputBuffers.Apply(); inputBuffers.Apply(gl);
if (draw->firstInstance > 0) { if (draw->firstInstance > 0) {
glDrawArraysInstancedBaseInstance(lastPipeline->GetGLPrimitiveTopology(), gl.DrawArraysInstancedBaseInstance(
draw->firstVertex, draw->vertexCount, lastPipeline->GetGLPrimitiveTopology(), draw->firstVertex,
draw->instanceCount, draw->firstInstance); draw->vertexCount, draw->instanceCount, draw->firstInstance);
} else { } else {
// This branch is only needed on OpenGL < 4.2 // This branch is only needed on OpenGL < 4.2
glDrawArraysInstanced(lastPipeline->GetGLPrimitiveTopology(), gl.DrawArraysInstanced(lastPipeline->GetGLPrimitiveTopology(),
draw->firstVertex, draw->vertexCount, draw->firstVertex, draw->vertexCount,
draw->instanceCount); draw->instanceCount);
} }
@ -695,7 +702,7 @@ namespace dawn_native { namespace opengl {
case Command::DrawIndexed: { case Command::DrawIndexed: {
DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>(); DrawIndexedCmd* draw = mCommands.NextCommand<DrawIndexedCmd>();
inputBuffers.Apply(); inputBuffers.Apply(gl);
dawn::IndexFormat indexFormat = dawn::IndexFormat indexFormat =
lastPipeline->GetVertexInputDescriptor()->indexFormat; lastPipeline->GetVertexInputDescriptor()->indexFormat;
@ -703,14 +710,14 @@ namespace dawn_native { namespace opengl {
GLenum formatType = IndexFormatType(indexFormat); GLenum formatType = IndexFormatType(indexFormat);
if (draw->firstInstance > 0) { if (draw->firstInstance > 0) {
glDrawElementsInstancedBaseVertexBaseInstance( gl.DrawElementsInstancedBaseVertexBaseInstance(
lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType, lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType,
reinterpret_cast<void*>(draw->firstIndex * formatSize + reinterpret_cast<void*>(draw->firstIndex * formatSize +
indexBufferBaseOffset), indexBufferBaseOffset),
draw->instanceCount, draw->baseVertex, draw->firstInstance); draw->instanceCount, draw->baseVertex, draw->firstInstance);
} else { } else {
// This branch is only needed on OpenGL < 4.2 // This branch is only needed on OpenGL < 4.2
glDrawElementsInstancedBaseVertex( gl.DrawElementsInstancedBaseVertex(
lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType, lastPipeline->GetGLPrimitiveTopology(), draw->indexCount, formatType,
reinterpret_cast<void*>(draw->firstIndex * formatSize + reinterpret_cast<void*>(draw->firstIndex * formatSize +
indexBufferBaseOffset), indexBufferBaseOffset),
@ -720,20 +727,20 @@ namespace dawn_native { namespace opengl {
case Command::DrawIndirect: { case Command::DrawIndirect: {
DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>(); DrawIndirectCmd* draw = mCommands.NextCommand<DrawIndirectCmd>();
inputBuffers.Apply(); inputBuffers.Apply(gl);
uint64_t indirectBufferOffset = draw->indirectOffset; uint64_t indirectBufferOffset = draw->indirectOffset;
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get()); Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle()); gl.BindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle());
glDrawArraysIndirect( gl.DrawArraysIndirect(
lastPipeline->GetGLPrimitiveTopology(), lastPipeline->GetGLPrimitiveTopology(),
reinterpret_cast<void*>(static_cast<intptr_t>(indirectBufferOffset))); reinterpret_cast<void*>(static_cast<intptr_t>(indirectBufferOffset)));
} break; } break;
case Command::DrawIndexedIndirect: { case Command::DrawIndexedIndirect: {
DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>(); DrawIndexedIndirectCmd* draw = mCommands.NextCommand<DrawIndexedIndirectCmd>();
inputBuffers.Apply(); inputBuffers.Apply(gl);
dawn::IndexFormat indexFormat = dawn::IndexFormat indexFormat =
lastPipeline->GetVertexInputDescriptor()->indexFormat; lastPipeline->GetVertexInputDescriptor()->indexFormat;
@ -742,8 +749,8 @@ namespace dawn_native { namespace opengl {
uint64_t indirectBufferOffset = draw->indirectOffset; uint64_t indirectBufferOffset = draw->indirectOffset;
Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get()); Buffer* indirectBuffer = ToBackend(draw->indirectBuffer.Get());
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle()); gl.BindBuffer(GL_DRAW_INDIRECT_BUFFER, indirectBuffer->GetHandle());
glDrawElementsIndirect( gl.DrawElementsIndirect(
lastPipeline->GetGLPrimitiveTopology(), formatType, lastPipeline->GetGLPrimitiveTopology(), formatType,
reinterpret_cast<void*>(static_cast<intptr_t>(indirectBufferOffset))); reinterpret_cast<void*>(static_cast<intptr_t>(indirectBufferOffset)));
} break; } break;
@ -766,22 +773,22 @@ namespace dawn_native { namespace opengl {
case Command::SetStencilReference: { case Command::SetStencilReference: {
SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>(); SetStencilReferenceCmd* cmd = mCommands.NextCommand<SetStencilReferenceCmd>();
persistentPipelineState.SetStencilReference(cmd->reference); persistentPipelineState.SetStencilReference(gl, cmd->reference);
} break; } break;
case Command::SetScissorRect: { case Command::SetScissorRect: {
SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>(); SetScissorRectCmd* cmd = mCommands.NextCommand<SetScissorRectCmd>();
glScissor(cmd->x, cmd->y, cmd->width, cmd->height); gl.Scissor(cmd->x, cmd->y, cmd->width, cmd->height);
} break; } break;
case Command::SetBlendColor: { case Command::SetBlendColor: {
SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>(); SetBlendColorCmd* cmd = mCommands.NextCommand<SetBlendColorCmd>();
glBlendColor(cmd->color.r, cmd->color.g, cmd->color.b, cmd->color.a); gl.BlendColor(cmd->color.r, cmd->color.g, cmd->color.b, cmd->color.a);
} break; } break;
case Command::SetBindGroup: { case Command::SetBindGroup: {
SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>(); SetBindGroupCmd* cmd = mCommands.NextCommand<SetBindGroupCmd>();
ApplyBindGroup(cmd->index, cmd->group.Get(), ApplyBindGroup(gl, cmd->index, cmd->group.Get(),
ToBackend(lastPipeline->GetLayout()), lastPipeline); ToBackend(lastPipeline->GetLayout()), lastPipeline);
} break; } break;

View File

@ -23,11 +23,11 @@ namespace dawn_native { namespace opengl {
PerStage<const ShaderModule*> modules(nullptr); PerStage<const ShaderModule*> modules(nullptr);
modules[dawn::ShaderStage::Compute] = ToBackend(descriptor->computeStage->module); modules[dawn::ShaderStage::Compute] = ToBackend(descriptor->computeStage->module);
PipelineGL::Initialize(ToBackend(descriptor->layout), modules); PipelineGL::Initialize(device->gl, ToBackend(descriptor->layout), modules);
} }
void ComputePipeline::ApplyNow() { void ComputePipeline::ApplyNow() {
PipelineGL::ApplyNow(); PipelineGL::ApplyNow(ToBackend(GetDevice())->gl);
} }
}} // namespace dawn_native::opengl }} // namespace dawn_native::opengl

View File

@ -31,8 +31,10 @@
namespace dawn_native { namespace opengl { namespace dawn_native { namespace opengl {
Device::Device(AdapterBase* adapter, const DeviceDescriptor* descriptor) Device::Device(AdapterBase* adapter,
: DeviceBase(adapter, descriptor) { const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions)
: DeviceBase(adapter, descriptor), gl(functions) {
if (descriptor != nullptr) { if (descriptor != nullptr) {
ApplyToggleOverrides(descriptor); ApplyToggleOverrides(descriptor);
} }
@ -102,7 +104,7 @@ namespace dawn_native { namespace opengl {
} }
void Device::SubmitFenceSync() { void Device::SubmitFenceSync() {
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); GLsync sync = gl.FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
mLastSubmittedSerial++; mLastSubmittedSerial++;
mFencesInFlight.emplace(sync, mLastSubmittedSerial); mFencesInFlight.emplace(sync, mLastSubmittedSerial);
} }
@ -130,12 +132,12 @@ namespace dawn_native { namespace opengl {
// Fence are added in order, so we can stop searching as soon // Fence are added in order, so we can stop searching as soon
// as we see one that's not ready. // as we see one that's not ready.
GLenum result = glClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0); GLenum result = gl.ClientWaitSync(sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0);
if (result == GL_TIMEOUT_EXPIRED) { if (result == GL_TIMEOUT_EXPIRED) {
continue; continue;
} }
glDeleteSync(sync); gl.DeleteSync(sync);
mFencesInFlight.pop(); mFencesInFlight.pop();

View File

@ -20,8 +20,7 @@
#include "common/Platform.h" #include "common/Platform.h"
#include "dawn_native/Device.h" #include "dawn_native/Device.h"
#include "dawn_native/opengl/Forward.h" #include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/OpenGLFunctions.h"
#include "glad/glad.h"
#include <queue> #include <queue>
@ -34,9 +33,14 @@ namespace dawn_native { namespace opengl {
class Device : public DeviceBase { class Device : public DeviceBase {
public: public:
Device(AdapterBase* adapter, const DeviceDescriptor* descriptor); Device(AdapterBase* adapter,
const DeviceDescriptor* descriptor,
const OpenGLFunctions& functions);
~Device(); ~Device();
// Contains all the OpenGL entry points, glDoFoo is called via device->gl.DoFoo.
const OpenGLFunctions gl;
void SubmitFenceSync(); void SubmitFenceSync();
// Dawn API // Dawn API

View File

@ -0,0 +1,59 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn_native/opengl/OpenGLFunctions.h"
#include <cctype>
namespace dawn_native { namespace opengl {
MaybeError OpenGLFunctions::Initialize(GetProcAddress getProc) {
PFNGLGETSTRINGPROC getString = reinterpret_cast<PFNGLGETSTRINGPROC>(getProc("glGetString"));
if (getString == nullptr) {
return DAWN_CONTEXT_LOST_ERROR("Couldn't load glGetString");
}
std::string version = reinterpret_cast<const char*>(getString(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"
mStandard = Standard::ES;
mMajorVersion = version[10] - '0';
mMinorVersion = version[12] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 13 || !isdigit(version[13]));
DAWN_TRY(LoadOpenGLESProcs(getProc, mMajorVersion, mMinorVersion));
} 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
mStandard = Standard::Desktop;
mMajorVersion = version[0] - '0';
mMinorVersion = version[2] - '0';
// The minor version shouldn't get to two digits.
ASSERT(version.size() <= 3 || !isdigit(version[3]));
DAWN_TRY(LoadDesktopGLProcs(getProc, mMajorVersion, mMinorVersion));
}
return {};
}
}} // namespace dawn_native::opengl

View File

@ -0,0 +1,39 @@
// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_
#define DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_
#include "dawn_native/opengl/OpenGLFunctionsBase_autogen.h"
namespace dawn_native { namespace opengl {
struct OpenGLFunctions : OpenGLFunctionsBase {
public:
MaybeError Initialize(GetProcAddress getProc);
private:
uint32_t mMajorVersion;
uint32_t mMinorVersion;
enum class Standard {
Desktop,
ES,
};
Standard mStandard;
};
}} // namespace dawn_native::opengl
#endif // DAWNNATIVE_OPENGL_OPENGLFUNCTIONS_H_

View File

@ -14,13 +14,16 @@
#include "dawn_native/opengl/PersistentPipelineStateGL.h" #include "dawn_native/opengl/PersistentPipelineStateGL.h"
#include "dawn_native/opengl/OpenGLFunctions.h"
namespace dawn_native { namespace opengl { namespace dawn_native { namespace opengl {
void PersistentPipelineState::SetDefaultState() { void PersistentPipelineState::SetDefaultState(const OpenGLFunctions& gl) {
CallGLStencilFunc(); CallGLStencilFunc(gl);
} }
void PersistentPipelineState::SetStencilFuncsAndMask(GLenum stencilBackCompareFunction, void PersistentPipelineState::SetStencilFuncsAndMask(const OpenGLFunctions& gl,
GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction, GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask) { uint32_t stencilReadMask) {
if (mStencilBackCompareFunction == stencilBackCompareFunction && if (mStencilBackCompareFunction == stencilBackCompareFunction &&
@ -32,22 +35,23 @@ namespace dawn_native { namespace opengl {
mStencilBackCompareFunction = stencilBackCompareFunction; mStencilBackCompareFunction = stencilBackCompareFunction;
mStencilFrontCompareFunction = stencilFrontCompareFunction; mStencilFrontCompareFunction = stencilFrontCompareFunction;
mStencilReadMask = stencilReadMask; mStencilReadMask = stencilReadMask;
CallGLStencilFunc(); CallGLStencilFunc(gl);
} }
void PersistentPipelineState::SetStencilReference(uint32_t stencilReference) { void PersistentPipelineState::SetStencilReference(const OpenGLFunctions& gl,
uint32_t stencilReference) {
if (mStencilReference == stencilReference) { if (mStencilReference == stencilReference) {
return; return;
} }
mStencilReference = stencilReference; mStencilReference = stencilReference;
CallGLStencilFunc(); CallGLStencilFunc(gl);
} }
void PersistentPipelineState::CallGLStencilFunc() { void PersistentPipelineState::CallGLStencilFunc(const OpenGLFunctions& gl) {
glStencilFuncSeparate(GL_BACK, mStencilBackCompareFunction, mStencilReference, gl.StencilFuncSeparate(GL_BACK, mStencilBackCompareFunction, mStencilReference,
mStencilReadMask); mStencilReadMask);
glStencilFuncSeparate(GL_FRONT, mStencilFrontCompareFunction, mStencilReference, gl.StencilFuncSeparate(GL_FRONT, mStencilFrontCompareFunction, mStencilReference,
mStencilReadMask); mStencilReadMask);
} }

View File

@ -21,16 +21,19 @@
namespace dawn_native { namespace opengl { namespace dawn_native { namespace opengl {
struct OpenGLFunctions;
class PersistentPipelineState { class PersistentPipelineState {
public: public:
void SetDefaultState(); void SetDefaultState(const OpenGLFunctions& gl);
void SetStencilFuncsAndMask(GLenum stencilBackCompareFunction, void SetStencilFuncsAndMask(const OpenGLFunctions& gl,
GLenum stencilBackCompareFunction,
GLenum stencilFrontCompareFunction, GLenum stencilFrontCompareFunction,
uint32_t stencilReadMask); uint32_t stencilReadMask);
void SetStencilReference(uint32_t stencilReference); void SetStencilReference(const OpenGLFunctions& gl, uint32_t stencilReference);
private: private:
void CallGLStencilFunc(); void CallGLStencilFunc(const OpenGLFunctions& gl);
GLenum mStencilBackCompareFunction = GL_ALWAYS; GLenum mStencilBackCompareFunction = GL_ALWAYS;
GLenum mStencilFrontCompareFunction = GL_ALWAYS; GLenum mStencilFrontCompareFunction = GL_ALWAYS;

View File

@ -17,7 +17,7 @@
#include "common/BitSetIterator.h" #include "common/BitSetIterator.h"
#include "dawn_native/BindGroupLayout.h" #include "dawn_native/BindGroupLayout.h"
#include "dawn_native/opengl/Forward.h" #include "dawn_native/opengl/Forward.h"
#include "dawn_native/opengl/PersistentPipelineStateGL.h" #include "dawn_native/opengl/OpenGLFunctions.h"
#include "dawn_native/opengl/PipelineLayoutGL.h" #include "dawn_native/opengl/PipelineLayoutGL.h"
#include "dawn_native/opengl/ShaderModuleGL.h" #include "dawn_native/opengl/ShaderModuleGL.h"
@ -46,22 +46,24 @@ namespace dawn_native { namespace opengl {
PipelineGL::PipelineGL() { PipelineGL::PipelineGL() {
} }
void PipelineGL::Initialize(const PipelineLayout* layout, void PipelineGL::Initialize(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<const ShaderModule*>& modules) { const PerStage<const ShaderModule*>& modules) {
auto CreateShader = [](GLenum type, const char* source) -> GLuint { auto CreateShader = [](const OpenGLFunctions& gl, GLenum type,
GLuint shader = glCreateShader(type); const char* source) -> GLuint {
glShaderSource(shader, 1, &source, nullptr); GLuint shader = gl.CreateShader(type);
glCompileShader(shader); gl.ShaderSource(shader, 1, &source, nullptr);
gl.CompileShader(shader);
GLint compileStatus = GL_FALSE; GLint compileStatus = GL_FALSE;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
if (compileStatus == GL_FALSE) { if (compileStatus == GL_FALSE) {
GLint infoLogLength = 0; GLint infoLogLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) { if (infoLogLength > 1) {
std::vector<char> buffer(infoLogLength); std::vector<char> buffer(infoLogLength);
glGetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]); gl.GetShaderInfoLog(shader, infoLogLength, nullptr, &buffer[0]);
std::cout << source << std::endl; std::cout << source << std::endl;
std::cout << "Program compilation failed:\n"; std::cout << "Program compilation failed:\n";
std::cout << buffer.data() << std::endl; std::cout << buffer.data() << std::endl;
@ -70,7 +72,7 @@ namespace dawn_native { namespace opengl {
return shader; return shader;
}; };
mProgram = glCreateProgram(); mProgram = gl.CreateProgram();
dawn::ShaderStageBit activeStages = dawn::ShaderStageBit::None; dawn::ShaderStageBit activeStages = dawn::ShaderStageBit::None;
for (dawn::ShaderStage stage : IterateStages(kAllStages)) { for (dawn::ShaderStage stage : IterateStages(kAllStages)) {
@ -80,27 +82,27 @@ namespace dawn_native { namespace opengl {
} }
for (dawn::ShaderStage stage : IterateStages(activeStages)) { for (dawn::ShaderStage stage : IterateStages(activeStages)) {
GLuint shader = CreateShader(GLShaderType(stage), modules[stage]->GetSource()); GLuint shader = CreateShader(gl, GLShaderType(stage), modules[stage]->GetSource());
glAttachShader(mProgram, shader); gl.AttachShader(mProgram, shader);
} }
glLinkProgram(mProgram); gl.LinkProgram(mProgram);
GLint linkStatus = GL_FALSE; GLint linkStatus = GL_FALSE;
glGetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus); gl.GetProgramiv(mProgram, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE) { if (linkStatus == GL_FALSE) {
GLint infoLogLength = 0; GLint infoLogLength = 0;
glGetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength); gl.GetProgramiv(mProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
if (infoLogLength > 1) { if (infoLogLength > 1) {
std::vector<char> buffer(infoLogLength); std::vector<char> buffer(infoLogLength);
glGetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]); gl.GetProgramInfoLog(mProgram, infoLogLength, nullptr, &buffer[0]);
std::cout << "Program link failed:\n"; std::cout << "Program link failed:\n";
std::cout << buffer.data() << std::endl; std::cout << buffer.data() << std::endl;
} }
} }
glUseProgram(mProgram); gl.UseProgram(mProgram);
// The uniforms are part of the program state so we can pre-bind buffer units, texture units // The uniforms are part of the program state so we can pre-bind buffer units, texture units
// etc. // etc.
@ -117,14 +119,14 @@ namespace dawn_native { namespace opengl {
std::string name = GetBindingName(group, binding); std::string name = GetBindingName(group, binding);
switch (groupInfo.types[binding]) { switch (groupInfo.types[binding]) {
case dawn::BindingType::UniformBuffer: { case dawn::BindingType::UniformBuffer: {
GLint location = glGetUniformBlockIndex(mProgram, name.c_str()); GLint location = gl.GetUniformBlockIndex(mProgram, name.c_str());
glUniformBlockBinding(mProgram, location, indices[group][binding]); gl.UniformBlockBinding(mProgram, location, indices[group][binding]);
} break; } break;
case dawn::BindingType::StorageBuffer: { case dawn::BindingType::StorageBuffer: {
GLuint location = glGetProgramResourceIndex( GLuint location = gl.GetProgramResourceIndex(
mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str()); mProgram, GL_SHADER_STORAGE_BLOCK, name.c_str());
glShaderStorageBlockBinding(mProgram, location, indices[group][binding]); gl.ShaderStorageBlockBinding(mProgram, location, indices[group][binding]);
} break; } break;
case dawn::BindingType::Sampler: case dawn::BindingType::Sampler:
@ -157,8 +159,8 @@ namespace dawn_native { namespace opengl {
GLuint textureUnit = layout->GetTextureUnitsUsed(); GLuint textureUnit = layout->GetTextureUnitsUsed();
for (const auto& combined : combinedSamplersSet) { for (const auto& combined : combinedSamplersSet) {
std::string name = combined.GetName(); std::string name = combined.GetName();
GLint location = glGetUniformLocation(mProgram, name.c_str()); GLint location = gl.GetUniformLocation(mProgram, name.c_str());
glUniform1i(location, textureUnit); gl.Uniform1i(location, textureUnit);
GLuint samplerIndex = GLuint samplerIndex =
indices[combined.samplerLocation.group][combined.samplerLocation.binding]; indices[combined.samplerLocation.group][combined.samplerLocation.binding];
@ -187,8 +189,8 @@ namespace dawn_native { namespace opengl {
return mProgram; return mProgram;
} }
void PipelineGL::ApplyNow() { void PipelineGL::ApplyNow(const OpenGLFunctions& gl) {
glUseProgram(mProgram); gl.UseProgram(mProgram);
} }
}} // namespace dawn_native::opengl }} // namespace dawn_native::opengl

View File

@ -23,7 +23,7 @@
namespace dawn_native { namespace opengl { namespace dawn_native { namespace opengl {
class Device; struct OpenGLFunctions;
class PersistentPipelineState; class PersistentPipelineState;
class PipelineLayout; class PipelineLayout;
class ShaderModule; class ShaderModule;
@ -32,7 +32,9 @@ namespace dawn_native { namespace opengl {
public: public:
PipelineGL(); PipelineGL();
void Initialize(const PipelineLayout* layout, const PerStage<const ShaderModule*>& modules); void Initialize(const OpenGLFunctions& gl,
const PipelineLayout* layout,
const PerStage<const ShaderModule*>& modules);
using BindingLocations = using BindingLocations =
std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>; std::array<std::array<GLint, kMaxBindingsPerGroup>, kMaxBindGroups>;
@ -41,7 +43,7 @@ namespace dawn_native { namespace opengl {
const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const; const std::vector<GLuint>& GetTextureUnitsForTextureView(GLuint index) const;
GLuint GetProgramHandle() const; GLuint GetProgramHandle() const;
void ApplyNow(); void ApplyNow(const OpenGLFunctions& gl);
private: private:
GLuint mProgram; GLuint mProgram;

View File

@ -90,20 +90,22 @@ namespace dawn_native { namespace opengl {
} }
} }
void ApplyColorState(uint32_t attachment, const ColorStateDescriptor* descriptor) { void ApplyColorState(const OpenGLFunctions& gl,
uint32_t attachment,
const ColorStateDescriptor* descriptor) {
if (BlendEnabled(descriptor)) { if (BlendEnabled(descriptor)) {
glEnablei(GL_BLEND, attachment); gl.Enablei(GL_BLEND, attachment);
glBlendEquationSeparatei(attachment, GLBlendMode(descriptor->colorBlend.operation), gl.BlendEquationSeparatei(attachment, GLBlendMode(descriptor->colorBlend.operation),
GLBlendMode(descriptor->alphaBlend.operation)); GLBlendMode(descriptor->alphaBlend.operation));
glBlendFuncSeparatei(attachment, gl.BlendFuncSeparatei(attachment,
GLBlendFactor(descriptor->colorBlend.srcFactor, false), GLBlendFactor(descriptor->colorBlend.srcFactor, false),
GLBlendFactor(descriptor->colorBlend.dstFactor, false), GLBlendFactor(descriptor->colorBlend.dstFactor, false),
GLBlendFactor(descriptor->alphaBlend.srcFactor, true), GLBlendFactor(descriptor->alphaBlend.srcFactor, true),
GLBlendFactor(descriptor->alphaBlend.dstFactor, true)); GLBlendFactor(descriptor->alphaBlend.dstFactor, true));
} else { } else {
glDisablei(GL_BLEND, attachment); gl.Disablei(GL_BLEND, attachment);
} }
glColorMaski(attachment, descriptor->writeMask & dawn::ColorWriteMask::Red, gl.ColorMaski(attachment, descriptor->writeMask & dawn::ColorWriteMask::Red,
descriptor->writeMask & dawn::ColorWriteMask::Green, descriptor->writeMask & dawn::ColorWriteMask::Green,
descriptor->writeMask & dawn::ColorWriteMask::Blue, descriptor->writeMask & dawn::ColorWriteMask::Blue,
descriptor->writeMask & dawn::ColorWriteMask::Alpha); descriptor->writeMask & dawn::ColorWriteMask::Alpha);
@ -132,43 +134,44 @@ namespace dawn_native { namespace opengl {
} }
} }
void ApplyDepthStencilState(const DepthStencilStateDescriptor* descriptor, void ApplyDepthStencilState(const OpenGLFunctions& gl,
const DepthStencilStateDescriptor* descriptor,
PersistentPipelineState* persistentPipelineState) { PersistentPipelineState* persistentPipelineState) {
// Depth writes only occur if depth is enabled // Depth writes only occur if depth is enabled
if (descriptor->depthCompare == dawn::CompareFunction::Always && if (descriptor->depthCompare == dawn::CompareFunction::Always &&
!descriptor->depthWriteEnabled) { !descriptor->depthWriteEnabled) {
glDisable(GL_DEPTH_TEST); gl.Disable(GL_DEPTH_TEST);
} else { } else {
glEnable(GL_DEPTH_TEST); gl.Enable(GL_DEPTH_TEST);
} }
if (descriptor->depthWriteEnabled) { if (descriptor->depthWriteEnabled) {
glDepthMask(GL_TRUE); gl.DepthMask(GL_TRUE);
} else { } else {
glDepthMask(GL_FALSE); gl.DepthMask(GL_FALSE);
} }
glDepthFunc(ToOpenGLCompareFunction(descriptor->depthCompare)); gl.DepthFunc(ToOpenGLCompareFunction(descriptor->depthCompare));
if (StencilTestEnabled(descriptor)) { if (StencilTestEnabled(descriptor)) {
glEnable(GL_STENCIL_TEST); gl.Enable(GL_STENCIL_TEST);
} else { } else {
glDisable(GL_STENCIL_TEST); gl.Disable(GL_STENCIL_TEST);
} }
GLenum backCompareFunction = ToOpenGLCompareFunction(descriptor->stencilBack.compare); GLenum backCompareFunction = ToOpenGLCompareFunction(descriptor->stencilBack.compare);
GLenum frontCompareFunction = ToOpenGLCompareFunction(descriptor->stencilFront.compare); GLenum frontCompareFunction = ToOpenGLCompareFunction(descriptor->stencilFront.compare);
persistentPipelineState->SetStencilFuncsAndMask( persistentPipelineState->SetStencilFuncsAndMask(
backCompareFunction, frontCompareFunction, descriptor->stencilReadMask); gl, backCompareFunction, frontCompareFunction, descriptor->stencilReadMask);
glStencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->stencilBack.failOp), gl.StencilOpSeparate(GL_BACK, OpenGLStencilOperation(descriptor->stencilBack.failOp),
OpenGLStencilOperation(descriptor->stencilBack.depthFailOp), OpenGLStencilOperation(descriptor->stencilBack.depthFailOp),
OpenGLStencilOperation(descriptor->stencilBack.passOp)); OpenGLStencilOperation(descriptor->stencilBack.passOp));
glStencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->stencilFront.failOp), gl.StencilOpSeparate(GL_FRONT, OpenGLStencilOperation(descriptor->stencilFront.failOp),
OpenGLStencilOperation(descriptor->stencilFront.depthFailOp), OpenGLStencilOperation(descriptor->stencilFront.depthFailOp),
OpenGLStencilOperation(descriptor->stencilFront.passOp)); OpenGLStencilOperation(descriptor->stencilFront.passOp));
glStencilMask(descriptor->stencilWriteMask); gl.StencilMask(descriptor->stencilWriteMask);
} }
} // anonymous namespace } // anonymous namespace
@ -181,13 +184,14 @@ namespace dawn_native { namespace opengl {
modules[dawn::ShaderStage::Vertex] = ToBackend(descriptor->vertexStage->module); modules[dawn::ShaderStage::Vertex] = ToBackend(descriptor->vertexStage->module);
modules[dawn::ShaderStage::Fragment] = ToBackend(descriptor->fragmentStage->module); modules[dawn::ShaderStage::Fragment] = ToBackend(descriptor->fragmentStage->module);
PipelineGL::Initialize(ToBackend(GetLayout()), modules); PipelineGL::Initialize(device->gl, ToBackend(GetLayout()), modules);
CreateVAOForVertexInput(descriptor->vertexInput); CreateVAOForVertexInput(descriptor->vertexInput);
} }
RenderPipeline::~RenderPipeline() { RenderPipeline::~RenderPipeline() {
glDeleteVertexArrays(1, &mVertexArrayObject); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
glBindVertexArray(0); gl.DeleteVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(0);
} }
GLenum RenderPipeline::GetGLPrimitiveTopology() const { GLenum RenderPipeline::GetGLPrimitiveTopology() const {
@ -195,11 +199,14 @@ namespace dawn_native { namespace opengl {
} }
void RenderPipeline::CreateVAOForVertexInput(const VertexInputDescriptor* vertexInput) { void RenderPipeline::CreateVAOForVertexInput(const VertexInputDescriptor* vertexInput) {
glGenVertexArrays(1, &mVertexArrayObject); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
glBindVertexArray(mVertexArrayObject);
gl.GenVertexArrays(1, &mVertexArrayObject);
gl.BindVertexArray(mVertexArrayObject);
for (uint32_t location : IterateBitSet(GetAttributesSetMask())) { for (uint32_t location : IterateBitSet(GetAttributesSetMask())) {
const auto& attribute = GetAttribute(location); const auto& attribute = GetAttribute(location);
glEnableVertexAttribArray(location); gl.EnableVertexAttribArray(location);
attributesUsingInput[attribute.inputSlot][location] = true; attributesUsingInput[attribute.inputSlot][location] = true;
auto input = GetInput(attribute.inputSlot); auto input = GetInput(attribute.inputSlot);
@ -207,13 +214,13 @@ namespace dawn_native { namespace opengl {
if (input.stride == 0) { if (input.stride == 0) {
// Emulate a stride of zero (constant vertex attribute) by // Emulate a stride of zero (constant vertex attribute) by
// setting the attribute instance divisor to a huge number. // setting the attribute instance divisor to a huge number.
glVertexAttribDivisor(location, 0xffffffff); gl.VertexAttribDivisor(location, 0xffffffff);
} else { } else {
switch (input.stepMode) { switch (input.stepMode) {
case dawn::InputStepMode::Vertex: case dawn::InputStepMode::Vertex:
break; break;
case dawn::InputStepMode::Instance: case dawn::InputStepMode::Instance:
glVertexAttribDivisor(location, 1); gl.VertexAttribDivisor(location, 1);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -223,15 +230,16 @@ namespace dawn_native { namespace opengl {
} }
void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) { void RenderPipeline::ApplyNow(PersistentPipelineState& persistentPipelineState) {
PipelineGL::ApplyNow(); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
PipelineGL::ApplyNow(gl);
ASSERT(mVertexArrayObject); ASSERT(mVertexArrayObject);
glBindVertexArray(mVertexArrayObject); gl.BindVertexArray(mVertexArrayObject);
ApplyDepthStencilState(GetDepthStencilStateDescriptor(), &persistentPipelineState); ApplyDepthStencilState(gl, GetDepthStencilStateDescriptor(), &persistentPipelineState);
for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) { for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
ApplyColorState(attachmentSlot, GetColorStateDescriptor(attachmentSlot)); ApplyColorState(gl, attachmentSlot, GetColorStateDescriptor(attachmentSlot));
} }
} }

View File

@ -74,20 +74,22 @@ namespace dawn_native { namespace opengl {
Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor) Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor)
: SamplerBase(device, descriptor) { : SamplerBase(device, descriptor) {
glGenSamplers(1, &mHandle); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
glSamplerParameteri(mHandle, GL_TEXTURE_MAG_FILTER, MagFilterMode(descriptor->magFilter));
glSamplerParameteri(mHandle, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
glSamplerParameteri(mHandle, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
glSamplerParameterf(mHandle, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp); gl.GenSamplers(1, &mHandle);
glSamplerParameterf(mHandle, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp); gl.SamplerParameteri(mHandle, GL_TEXTURE_MAG_FILTER, MagFilterMode(descriptor->magFilter));
gl.SamplerParameteri(mHandle, GL_TEXTURE_MIN_FILTER,
MinFilterMode(descriptor->minFilter, descriptor->mipmapFilter));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_R, WrapMode(descriptor->addressModeW));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_S, WrapMode(descriptor->addressModeU));
gl.SamplerParameteri(mHandle, GL_TEXTURE_WRAP_T, WrapMode(descriptor->addressModeV));
gl.SamplerParameterf(mHandle, GL_TEXTURE_MIN_LOD, descriptor->lodMinClamp);
gl.SamplerParameterf(mHandle, GL_TEXTURE_MAX_LOD, descriptor->lodMaxClamp);
if (ToOpenGLCompareFunction(descriptor->compareFunction) != GL_NEVER) { if (ToOpenGLCompareFunction(descriptor->compareFunction) != GL_NEVER) {
glSamplerParameteri(mHandle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
glSamplerParameteri(mHandle, GL_TEXTURE_COMPARE_FUNC, gl.SamplerParameteri(mHandle, GL_TEXTURE_COMPARE_FUNC,
ToOpenGLCompareFunction(descriptor->compareFunction)); ToOpenGLCompareFunction(descriptor->compareFunction));
} }
} }

View File

@ -88,9 +88,9 @@ namespace dawn_native { namespace opengl {
} }
} }
GLuint GenTexture() { GLuint GenTexture(const OpenGLFunctions& gl) {
GLuint handle = 0; GLuint handle = 0;
glGenTextures(1, &handle); gl.GenTextures(1, &handle);
return handle; return handle;
} }
@ -130,7 +130,9 @@ namespace dawn_native { namespace opengl {
// Texture // Texture
Texture::Texture(Device* device, const TextureDescriptor* descriptor) Texture::Texture(Device* device, const TextureDescriptor* descriptor)
: Texture(device, descriptor, GenTexture(), TextureState::OwnedInternal) { : Texture(device, descriptor, GenTexture(device->gl), TextureState::OwnedInternal) {
const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
uint32_t width = GetSize().width; uint32_t width = GetSize().width;
uint32_t height = GetSize().height; uint32_t height = GetSize().height;
uint32_t levels = GetNumMipLevels(); uint32_t levels = GetNumMipLevels();
@ -139,7 +141,7 @@ namespace dawn_native { namespace opengl {
auto formatInfo = GetGLFormatInfo(GetFormat()); auto formatInfo = GetGLFormatInfo(GetFormat());
glBindTexture(mTarget, mHandle); gl.BindTexture(mTarget, mHandle);
// glTextureView() requires the value of GL_TEXTURE_IMMUTABLE_FORMAT for origtexture to be // glTextureView() requires the value of GL_TEXTURE_IMMUTABLE_FORMAT for origtexture to be
// GL_TRUE, so the storage of the texture must be allocated with glTexStorage*D. // GL_TRUE, so the storage of the texture must be allocated with glTexStorage*D.
@ -148,14 +150,14 @@ namespace dawn_native { namespace opengl {
case dawn::TextureDimension::e2D: case dawn::TextureDimension::e2D:
if (arrayLayers > 1) { if (arrayLayers > 1) {
ASSERT(!IsMultisampledTexture()); ASSERT(!IsMultisampledTexture());
glTexStorage3D(mTarget, levels, formatInfo.internalFormat, width, height, gl.TexStorage3D(mTarget, levels, formatInfo.internalFormat, width, height,
arrayLayers); arrayLayers);
} else { } else {
if (IsMultisampledTexture()) { if (IsMultisampledTexture()) {
glTexStorage2DMultisample(mTarget, sampleCount, formatInfo.internalFormat, gl.TexStorage2DMultisample(mTarget, sampleCount, formatInfo.internalFormat,
width, height, true); width, height, true);
} else { } else {
glTexStorage2D(mTarget, levels, formatInfo.internalFormat, width, height); gl.TexStorage2D(mTarget, levels, formatInfo.internalFormat, width, height);
} }
} }
break; break;
@ -165,7 +167,7 @@ namespace dawn_native { namespace opengl {
// The texture is not complete if it uses mipmapping and not all levels up to // The texture is not complete if it uses mipmapping and not all levels up to
// MAX_LEVEL have been defined. // MAX_LEVEL have been defined.
glTexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1); gl.TexParameteri(mTarget, GL_TEXTURE_MAX_LEVEL, levels - 1);
if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) { if (GetDevice()->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
static constexpr uint32_t MAX_TEXEL_SIZE = 16; static constexpr uint32_t MAX_TEXEL_SIZE = 16;
@ -175,7 +177,7 @@ namespace dawn_native { namespace opengl {
// TODO(natlee@microsoft.com): clear all subresources // TODO(natlee@microsoft.com): clear all subresources
for (uint32_t i = 0; i < GL_TEXTURE_MAX_LEVEL; i++) { for (uint32_t i = 0; i < GL_TEXTURE_MAX_LEVEL; i++) {
glClearTexImage(mHandle, i, formatInfo.format, formatInfo.type, clearColor); gl.ClearTexImage(mHandle, i, formatInfo.format, formatInfo.type, clearColor);
} }
} }
} }
@ -193,7 +195,7 @@ namespace dawn_native { namespace opengl {
} }
void Texture::DestroyImpl() { void Texture::DestroyImpl() {
glDeleteTextures(1, &mHandle); ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
mHandle = 0; mHandle = 0;
} }
@ -222,10 +224,11 @@ namespace dawn_native { namespace opengl {
} else { } else {
// glTextureView() is supported on OpenGL version >= 4.3 // glTextureView() is supported on OpenGL version >= 4.3
// TODO(jiawei.shao@intel.com): support texture view on OpenGL version <= 4.2 // TODO(jiawei.shao@intel.com): support texture view on OpenGL version <= 4.2
mHandle = GenTexture(); const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
mHandle = GenTexture(gl);
const Texture* textureGL = ToBackend(texture); const Texture* textureGL = ToBackend(texture);
TextureFormatInfo textureViewFormat = GetGLFormatInfo(descriptor->format); TextureFormatInfo textureViewFormat = GetGLFormatInfo(descriptor->format);
glTextureView(mHandle, mTarget, textureGL->GetHandle(), gl.TextureView(mHandle, mTarget, textureGL->GetHandle(),
textureViewFormat.internalFormat, descriptor->baseMipLevel, textureViewFormat.internalFormat, descriptor->baseMipLevel,
descriptor->mipLevelCount, descriptor->baseArrayLayer, descriptor->mipLevelCount, descriptor->baseArrayLayer,
descriptor->arrayLayerCount); descriptor->arrayLayerCount);
@ -235,7 +238,7 @@ namespace dawn_native { namespace opengl {
TextureView::~TextureView() { TextureView::~TextureView() {
if (mOwnsHandle) { if (mOwnsHandle) {
glDeleteTextures(1, &mHandle); ToBackend(GetDevice())->gl.DeleteTextures(1, &mHandle);
} }
} }

50579
third_party/gl.xml vendored Normal file

File diff suppressed because it is too large Load Diff