Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/glimp/egl/attrib_map.cc b/src/glimp/egl/attrib_map.cc
new file mode 100644
index 0000000..97af886
--- /dev/null
+++ b/src/glimp/egl/attrib_map.cc
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/attrib_map.h"
+
+namespace glimp {
+namespace egl {
+
+AttribMap ParseRawAttribList(const EGLint* attrib_list) {
+ AttribMap ret;
+ if (!attrib_list) {
+ return ret;
+ }
+
+ const int* current_attrib = attrib_list;
+ while (*current_attrib != EGL_NONE) {
+ int key = *current_attrib++;
+ int value = *current_attrib++;
+
+ ret[key] = value;
+ }
+
+ return ret;
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/attrib_map.h b/src/glimp/egl/attrib_map.h
new file mode 100644
index 0000000..62fe5ac
--- /dev/null
+++ b/src/glimp/egl/attrib_map.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_ATTRIB_MAP_H_
+#define GLIMP_EGL_ATTRIB_MAP_H_
+
+#include <EGL/egl.h>
+
+#include <map>
+
+namespace glimp {
+namespace egl {
+
+typedef std::map<int, int> AttribMap;
+
+// Many EGL functions take an "attribute list" as a parameter that all share a
+// similar format: A list of integer key/value pairs and concluded with the
+// value EGL_NONE (like a null terminated C string). This function parses
+// that attribute list into a map and returns it.
+AttribMap ParseRawAttribList(const EGLint* attrib_list);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_ATTRIB_MAP_H_
diff --git a/src/glimp/egl/config.cc b/src/glimp/egl/config.cc
new file mode 100644
index 0000000..1af0678
--- /dev/null
+++ b/src/glimp/egl/config.cc
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/config.h"
+
+#include <algorithm>
+
+#include "starboard/log.h"
+
+namespace glimp {
+namespace egl {
+
+namespace {
+bool AttributeKeyAndValueAreValid(int key, int value) {
+ switch (key) {
+ // Deal with the size keys where all values are valid.
+ case EGL_RED_SIZE:
+ case EGL_GREEN_SIZE:
+ case EGL_BLUE_SIZE:
+ case EGL_ALPHA_SIZE:
+ case EGL_BUFFER_SIZE:
+ case EGL_LUMINANCE_SIZE:
+ case EGL_STENCIL_SIZE: {
+ return true;
+ }
+
+ // Deal with the mask keys where all values are valid.
+ case EGL_CONFORMANT:
+ case EGL_RENDERABLE_TYPE:
+ case EGL_SURFACE_TYPE: {
+ return true;
+ }
+
+ // Deal with boolean values.
+ case EGL_BIND_TO_TEXTURE_RGBA: {
+ switch (value) {
+ case EGL_DONT_CARE:
+ case EGL_TRUE:
+ case EGL_FALSE: {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ case EGL_COLOR_BUFFER_TYPE: {
+ switch (value) {
+ case EGL_RGB_BUFFER:
+ case EGL_LUMINANCE_BUFFER: {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ // If the switch statement didn't catch the key, this is an unknown
+ // key values.
+ // TODO: glimp doesn't support all values yet, and will return false for keys
+ // that it doesn't support.
+ return false;
+}
+} // namespace
+
+bool ValidateConfigAttribList(const AttribMap& attribs) {
+ for (AttribMap::const_iterator iter = attribs.begin(); iter != attribs.end();
+ ++iter) {
+ if (!AttributeKeyAndValueAreValid(iter->first, iter->second)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+namespace {
+// Returns whether or not a single attribute (the parameters |key| and |value|)
+// matches a config or not.
+bool ConfigMatchesAttribute(const Config& config, int key, int value) {
+ SB_DCHECK(AttributeKeyAndValueAreValid(key, value));
+ SB_DCHECK(value != EGL_DONT_CARE);
+
+ switch (key) {
+ case EGL_RED_SIZE:
+ case EGL_GREEN_SIZE:
+ case EGL_BLUE_SIZE:
+ case EGL_ALPHA_SIZE:
+ case EGL_BUFFER_SIZE:
+ case EGL_LUMINANCE_SIZE:
+ case EGL_STENCIL_SIZE: {
+ // We match if our config's bit depth is greater than or equal to the
+ // requested value.
+ return config.find(key)->second >= value;
+ }
+
+ case EGL_CONFORMANT:
+ case EGL_RENDERABLE_TYPE:
+ case EGL_SURFACE_TYPE: {
+ // We match if our config's bit mask includes the requested bit mask.
+ return (config.find(key)->second & value) == value;
+ }
+
+ case EGL_BIND_TO_TEXTURE_RGBA: {
+ // Our config matches booleans if the requested boolean is not true, or
+ // else if the config's corresponding boolean is also true.
+ return value != EGL_TRUE || config.find(key)->second == EGL_TRUE;
+ }
+
+ case EGL_COLOR_BUFFER_TYPE: {
+ // We match if our config value matches the requested value exactly.
+ return config.find(key)->second == value;
+ }
+ }
+
+ // The attributes should have been validated when this function is called,
+ // so if we reach this point, then there is an inconsistency between
+ // this function and AttributeKeyAndValueAreValid().
+ SB_NOTREACHED();
+ return false;
+}
+
+bool ConfigMatchesAttributes(const Config& config,
+ const AttribMap& attrib_list) {
+ for (AttribMap::const_iterator iter = attrib_list.begin();
+ iter != attrib_list.end(); ++iter) {
+ if (iter->second != EGL_DONT_CARE) {
+ if (!ConfigMatchesAttribute(config, iter->first, iter->second)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+} // namespace
+
+std::vector<Config*> FilterConfigs(const std::set<Config*>& configs,
+ const AttribMap& attrib_list) {
+ std::vector<Config*> ret;
+
+ for (std::set<Config*>::const_iterator iter = configs.begin();
+ iter != configs.end(); ++iter) {
+ if (ConfigMatchesAttributes(**iter, attrib_list)) {
+ ret.push_back(*iter);
+ }
+ }
+
+ return ret;
+}
+
+namespace {
+
+class ConfigSorter {
+ public:
+ explicit ConfigSorter(const AttribMap& attrib_list)
+ : attrib_list_(attrib_list) {}
+
+ // We define this such that it sorts in decreasing order of preference.
+ bool operator()(const Config* lhs, const Config* rhs) const {
+ // Bit depth must be sorted in ascending order as a total over all
+ // channels that are specified by the config.
+ if (GetTotalBitDepth(*lhs) > GetTotalBitDepth(*rhs)) {
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ // Returns the bit depth for a given channel, or 0 if we don't care about
+ // it's value (e.g. it is not in the specified attribute list).
+ int GetTotalBitDepthForChannel(const Config& config, int key) const {
+ AttribMap::const_iterator found = attrib_list_.find(key);
+ if (found == attrib_list_.end() || found->second == EGL_DONT_CARE) {
+ return 0;
+ } else {
+ return found->second;
+ }
+ }
+
+ // Gets the total depth for all color channels, to be used to decide the
+ // sort order.
+ int GetTotalBitDepth(const Config& config) const {
+ int total_bit_depth = 0;
+ total_bit_depth += GetTotalBitDepthForChannel(config, EGL_RED_SIZE);
+ total_bit_depth += GetTotalBitDepthForChannel(config, EGL_GREEN_SIZE);
+ total_bit_depth += GetTotalBitDepthForChannel(config, EGL_BLUE_SIZE);
+ total_bit_depth += GetTotalBitDepthForChannel(config, EGL_ALPHA_SIZE);
+ return total_bit_depth;
+ }
+
+ const AttribMap& attrib_list_;
+};
+} // namespace
+
+void SortConfigs(const AttribMap& attrib_list,
+ std::vector<Config*>* in_out_configs) {
+ ConfigSorter config_sorter(attrib_list);
+ std::sort(in_out_configs->begin(), in_out_configs->end(), config_sorter);
+}
+
+EGLConfig ToEGLConfig(Config* config) {
+ return reinterpret_cast<EGLConfig>(config);
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/config.h b/src/glimp/egl/config.h
new file mode 100644
index 0000000..5ac18fd
--- /dev/null
+++ b/src/glimp/egl/config.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_CONFIG_H_
+#define GLIMP_EGL_CONFIG_H_
+
+#include <EGL/egl.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "glimp/egl/attrib_map.h"
+
+namespace glimp {
+namespace egl {
+
+// Our underlying EGLConfig structure is just a mapping from config key to
+// value.
+typedef std::map<int, int> Config;
+
+// Examines the |attribs| list of attributes passed in to eglGetConfig(), and
+// checks if the attributes are invalid, in which case false is returned,
+// otherwise true is returned.
+bool ValidateConfigAttribList(const AttribMap& attribs);
+
+// Filters the input configs such that only those that match the specified
+// |attrib_list| are returned.
+std::vector<Config*> FilterConfigs(const std::set<Config*>& configs,
+ const AttribMap& attrib_list);
+
+// Sorts the input list in place according to what best metches the specified
+// |attrib_list|. |in_out_configs| will be sorted after this function returns.
+void SortConfigs(const AttribMap& attrib_list,
+ std::vector<Config*>* in_out_configs);
+
+// Convert our internal Config pointer type into a public EGLConfig type.
+EGLConfig ToEGLConfig(Config* config);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_CONFIG_H_
diff --git a/src/glimp/egl/display.cc b/src/glimp/egl/display.cc
new file mode 100644
index 0000000..0d02a74
--- /dev/null
+++ b/src/glimp/egl/display.cc
@@ -0,0 +1,313 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/display.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "glimp/egl/config.h"
+#include "glimp/egl/error.h"
+#include "starboard/log.h"
+
+namespace glimp {
+namespace egl {
+
+Display::Display(nb::scoped_ptr<DisplayImpl> display_impl)
+ : impl_(display_impl.Pass()) {}
+
+Display::~Display() {
+ SB_DCHECK(active_surfaces_.empty());
+}
+
+void Display::GetVersionInfo(EGLint* major, EGLint* minor) {
+ DisplayImpl::VersionInfo version_info = impl_->GetVersionInfo();
+ if (major) {
+ *major = version_info.major;
+ }
+ if (minor) {
+ *minor = version_info.minor;
+ }
+}
+
+bool Display::ChooseConfig(const EGLint* attrib_list,
+ EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config) {
+ if (!num_config) {
+ SetError(EGL_BAD_PARAMETER);
+ return false;
+ }
+ AttribMap attribs = ParseRawAttribList(attrib_list);
+ if (!ValidateConfigAttribList(attribs)) {
+ SetError(EGL_BAD_ATTRIBUTE);
+ return false;
+ }
+
+ std::vector<Config*> configs_vector =
+ FilterConfigs(impl_->GetSupportedConfigs(), attribs);
+ SortConfigs(attribs, &configs_vector);
+
+ if (configs) {
+ *num_config =
+ std::min(config_size, static_cast<int>(configs_vector.size()));
+ for (int i = 0; i < *num_config; ++i) {
+ configs[i] = ToEGLConfig(configs_vector[i]);
+ }
+ } else {
+ *num_config = static_cast<int>(configs_vector.size());
+ }
+
+ return true;
+}
+
+bool Display::ConfigIsValid(EGLConfig config) {
+ const DisplayImpl::ConfigSet& supported_configs =
+ impl_->GetSupportedConfigs();
+
+ return supported_configs.find(reinterpret_cast<Config*>(config)) !=
+ supported_configs.end();
+}
+
+EGLSurface Display::CreateWindowSurface(EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint* attrib_list) {
+ AttribMap attribs = ParseRawAttribList(attrib_list);
+ if (!ValidateSurfaceAttribList(attribs)) {
+ SetError(EGL_BAD_ATTRIBUTE);
+ return EGL_NO_SURFACE;
+ }
+
+ if (!ConfigIsValid(config)) {
+ SetError(EGL_BAD_CONFIG);
+ return EGL_NO_SURFACE;
+ }
+
+ if (!((*reinterpret_cast<Config*>(config))[EGL_SURFACE_TYPE] |
+ EGL_WINDOW_BIT)) {
+ // The config used must have the EGL_WINDOW_BIT set in order for us to
+ // be able to create windows.
+ SetError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+
+ nb::scoped_ptr<SurfaceImpl> surface_impl = impl_->CreateWindowSurface(
+ reinterpret_cast<Config*>(config), win, attribs);
+ if (!surface_impl) {
+ return EGL_NO_SURFACE;
+ }
+
+ Surface* surface = new Surface(surface_impl.Pass());
+ active_surfaces_.insert(surface);
+
+ return ToEGLSurface(surface);
+}
+
+EGLSurface Display::CreatePbufferSurface(EGLConfig config,
+ const EGLint* attrib_list) {
+ AttribMap attribs = ParseRawAttribList(attrib_list);
+ if (!ValidateSurfaceAttribList(attribs)) {
+ SetError(EGL_BAD_ATTRIBUTE);
+ return EGL_NO_SURFACE;
+ }
+
+ if (!ConfigIsValid(config)) {
+ SetError(EGL_BAD_CONFIG);
+ return EGL_NO_SURFACE;
+ }
+
+ if (!((*reinterpret_cast<Config*>(config))[EGL_SURFACE_TYPE] |
+ EGL_PBUFFER_BIT)) {
+ // The config used must have the EGL_PBUFFER_BIT set in order for us to
+ // be able to create pbuffers.
+ SetError(EGL_BAD_MATCH);
+ return EGL_NO_SURFACE;
+ }
+
+ nb::scoped_ptr<SurfaceImpl> surface_impl =
+ impl_->CreatePbufferSurface(reinterpret_cast<Config*>(config), attribs);
+ if (!surface_impl) {
+ return EGL_NO_SURFACE;
+ }
+
+ Surface* surface = new Surface(surface_impl.Pass());
+ active_surfaces_.insert(surface);
+
+ return ToEGLSurface(surface);
+}
+
+bool Display::SurfaceIsValid(EGLSurface surface) {
+ return active_surfaces_.find(FromEGLSurface(surface)) !=
+ active_surfaces_.end();
+}
+
+bool Display::DestroySurface(EGLSurface surface) {
+ if (!SurfaceIsValid(surface)) {
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+
+ Surface* surf = FromEGLSurface(surface);
+ active_surfaces_.erase(surf);
+ delete surf;
+ return true;
+}
+
+namespace {
+// Returns -1 if the context attributes are invalid.
+int GetContextVersion(const EGLint* attrib_list) {
+ AttribMap attribs = ParseRawAttribList(attrib_list);
+
+ // According to
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglCreateContext.xhtml,
+ // the default version of the GL ES context is 1.
+ if (attribs.empty()) {
+ return 1;
+ }
+
+ // EGL_CONTEXT_CLIENT_VERSION is the only valid attribute for CreateContext.
+ AttribMap::const_iterator found = attribs.find(EGL_CONTEXT_CLIENT_VERSION);
+ if (found == attribs.end()) {
+ // If we didn't find it, and the attribute list is not empty (checked above)
+ // then this is an invalid attribute list.
+ return -1;
+ } else {
+ return found->second;
+ }
+}
+} // namespace
+
+EGLContext Display::CreateContext(EGLConfig config,
+ EGLContext share_context,
+ const EGLint* attrib_list) {
+ // glimp only supports GL ES versions 2 and 3.
+ int context_version = GetContextVersion(attrib_list);
+ if (context_version != 2 && context_version != 3) {
+ SetError(EGL_BAD_ATTRIBUTE);
+ return EGL_NO_CONTEXT;
+ }
+
+ if (!ConfigIsValid(config)) {
+ SetError(EGL_BAD_CONFIG);
+ return EGL_NO_CONTEXT;
+ }
+
+ // Ensure that |share_context| is either unspecified, or valid.
+ gles::Context* share = NULL;
+ if (share_context != EGL_NO_CONTEXT) {
+ if (!ContextIsValid(share_context)) {
+ SetError(EGL_BAD_CONTEXT);
+ return EGL_NO_CONTEXT;
+ }
+ share = reinterpret_cast<gles::Context*>(share_context);
+ }
+
+ nb::scoped_ptr<gles::ContextImpl> context_impl =
+ impl_->CreateContext(reinterpret_cast<Config*>(config), context_version);
+ if (!context_impl) {
+ return EGL_NO_CONTEXT;
+ }
+
+ gles::Context* context = new gles::Context(context_impl.Pass(), share);
+ active_contexts_.insert(context);
+
+ return reinterpret_cast<EGLContext>(context);
+}
+
+bool Display::ContextIsValid(EGLContext context) {
+ return active_contexts_.find(reinterpret_cast<gles::Context*>(context)) !=
+ active_contexts_.end();
+}
+
+bool Display::DestroyContext(EGLContext ctx) {
+ if (!ContextIsValid(ctx)) {
+ SetError(EGL_BAD_CONTEXT);
+ return false;
+ }
+
+ gles::Context* context = reinterpret_cast<gles::Context*>(ctx);
+ active_contexts_.erase(context);
+ delete context;
+ return true;
+}
+
+bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
+ if (draw == EGL_NO_SURFACE && read == EGL_NO_SURFACE &&
+ ctx == EGL_NO_CONTEXT) {
+ if (!ContextIsValid(reinterpret_cast<EGLContext>(
+ gles::Context::GetTLSCurrentContext()))) {
+ SB_DLOG(WARNING)
+ << "Attempted to release a context not owned by this display.";
+ SetError(EGL_BAD_CONTEXT);
+ return false;
+ }
+ gles::Context::ReleaseTLSCurrentContext();
+ return true;
+ }
+
+ if (!ContextIsValid(ctx)) {
+ SetError(EGL_BAD_CONTEXT);
+ return false;
+ }
+
+ if (!SurfaceIsValid(draw)) {
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+
+ if (!SurfaceIsValid(read)) {
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+
+ return gles::Context::SetTLSCurrentContext(
+ reinterpret_cast<gles::Context*>(ctx), FromEGLSurface(draw),
+ FromEGLSurface(read));
+}
+
+bool Display::SwapBuffers(EGLSurface surface) {
+ if (!SurfaceIsValid(surface)) {
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+ Surface* surface_object = FromEGLSurface(surface);
+
+ gles::Context* current_context = gles::Context::GetTLSCurrentContext();
+ if (!ContextIsValid(reinterpret_cast<EGLContext>(current_context))) {
+ // The specification for eglSwapBuffers() does not explicitly state that
+ // the surface's context needs to be current when eglSwapBuffers() is
+ // called, but we enforce this in glimp as it is a very typical use-case and
+ // it considerably simplifies the process.
+ SB_DLOG(WARNING)
+ << "eglSwapBuffers() called when no or an invalid context was current.";
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+
+ if (current_context->draw_surface() != surface_object) {
+ SB_DLOG(WARNING)
+ << "eglSwapBuffers() called on a surface that is not the draw surface "
+ << "of the current context.";
+ SetError(EGL_BAD_SURFACE);
+ return false;
+ }
+
+ current_context->SwapBuffers();
+ return true;
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/display.h b/src/glimp/egl/display.h
new file mode 100644
index 0000000..a61469a
--- /dev/null
+++ b/src/glimp/egl/display.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_DISPLAY_H_
+#define GLIMP_EGL_DISPLAY_H_
+
+#include <set>
+
+#include "glimp/egl/config.h"
+#include "glimp/egl/display_impl.h"
+#include "glimp/gles/context.h"
+#include "nb/scoped_ptr.h"
+
+namespace glimp {
+namespace egl {
+
+// Encapsulates the concept of an EGL display. There is usually only one of
+// these per process, and it represents the entire graphics system. It is
+// the highest level object, and the "factory" responsible for generating
+// graphics contexts. It is a platform-independent object that wraps a
+// platform-dependent DisplayImpl object which must be injected into the Display
+// upon construction.
+class Display {
+ public:
+ // In order to create a display, it must have a platform-specific
+ // implementation injected into it, where many methods will forward to.
+ explicit Display(nb::scoped_ptr<DisplayImpl> display_impl);
+ ~Display();
+
+ void GetVersionInfo(EGLint* major, EGLint* minor);
+
+ bool ChooseConfig(const EGLint* attrib_list,
+ EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config);
+ bool ConfigIsValid(EGLConfig config);
+
+ EGLSurface CreateWindowSurface(EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint* attrib_list);
+ EGLSurface CreatePbufferSurface(EGLConfig config, const EGLint* attrib_list);
+
+ bool SurfaceIsValid(EGLSurface surface);
+ bool DestroySurface(EGLSurface surface);
+
+ EGLContext CreateContext(EGLConfig config,
+ EGLContext share_context,
+ const EGLint* attrib_list);
+ bool ContextIsValid(EGLContext context);
+ bool DestroyContext(EGLContext ctx);
+
+ bool MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx);
+ bool SwapBuffers(EGLSurface surface);
+
+ DisplayImpl* impl() const { return impl_.get(); }
+
+ private:
+ nb::scoped_ptr<DisplayImpl> impl_;
+
+ // Keeps track of all created but not destroyed surfaces.
+ std::set<Surface*> active_surfaces_;
+
+ // Keeps track of all created but not destroyed contexts.
+ std::set<gles::Context*> active_contexts_;
+};
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_DISPLAY_H_
diff --git a/src/glimp/egl/display_impl.h b/src/glimp/egl/display_impl.h
new file mode 100644
index 0000000..c430202
--- /dev/null
+++ b/src/glimp/egl/display_impl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_DISPLAY_IMPL_H_
+#define GLIMP_EGL_DISPLAY_IMPL_H_
+
+#include <EGL/egl.h>
+
+#include <set>
+
+#include "glimp/egl/attrib_map.h"
+#include "glimp/egl/config.h"
+#include "glimp/egl/surface.h"
+#include "glimp/gles/context_impl.h"
+#include "nb/scoped_ptr.h"
+
+namespace glimp {
+namespace egl {
+
+// All platform-specific aspects of a EGL Display are implemented within
+// subclasses of DisplayImpl. Platforms must also implement
+// DisplayImpl::Create(), declared below, in order to define how
+// platform-specific DisplayImpls are to be created.
+class DisplayImpl {
+ public:
+ // Return value type for the method GetVersionInfo().
+ struct VersionInfo {
+ int major;
+ int minor;
+ };
+
+ typedef std::set<Config*> ConfigSet;
+
+ virtual ~DisplayImpl() {}
+
+ // Returns true if the given |native_display| is a valid display ID that can
+ // be subsequently passed into Create().
+ // To be implemented by each implementing platform.
+ static bool IsValidNativeDisplayType(EGLNativeDisplayType display_id);
+ // Creates and returns a new DisplayImpl object.
+ // To be implemented by each implementing platform.
+ static nb::scoped_ptr<DisplayImpl> Create(EGLNativeDisplayType display_id);
+
+ // Returns the EGL major and minor versions, if they are not NULL.
+ // Called by eglInitialize():
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglInitialize.xhtml
+ virtual VersionInfo GetVersionInfo() = 0;
+
+ // Returns *all* configs for this display that may be chosen via a call to
+ // eglChooseConfig().
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglChooseConfig.xhtml
+ virtual const ConfigSet& GetSupportedConfigs() const = 0;
+
+ // Creates and returns a SurfaceImpl object that represents the surface of a
+ // window and is compatible with this DisplayImpl object. This will be called
+ // when eglCreateWindowSurface() is called.
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglCreateWindowSurface.xhtml
+ virtual nb::scoped_ptr<SurfaceImpl> CreateWindowSurface(
+ const Config* config,
+ EGLNativeWindowType win,
+ const AttribMap& attributes) = 0;
+
+ // Creates and returns a SurfaceImpl object that represents the surface of a
+ // Pbuffer and is compatible with this DisplayImpl object. This will be
+ // called when eglCreatePbufferSurface() is called.
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglCreatePbufferSurface.xhtml
+ virtual nb::scoped_ptr<SurfaceImpl> CreatePbufferSurface(
+ const Config* config,
+ const AttribMap& attributes) = 0;
+
+ // Creates and returns a gles::ContextImpl object that contains the platform
+ // specific implementation of a GL ES Context, of the specified version that
+ // is compatible with the specified config.
+ virtual nb::scoped_ptr<gles::ContextImpl> CreateContext(const Config* config,
+ int gles_version) = 0;
+
+ private:
+};
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_DISPLAY_IMPL_H_
diff --git a/src/glimp/egl/display_registry.cc b/src/glimp/egl/display_registry.cc
new file mode 100644
index 0000000..c2f1d2d
--- /dev/null
+++ b/src/glimp/egl/display_registry.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/display_registry.h"
+
+#include "glimp/egl/display_impl.h"
+#include "glimp/egl/error.h"
+
+namespace glimp {
+namespace egl {
+
+int DisplayRegistry::num_connections_ = 0;
+DisplayRegistry::Connection
+ DisplayRegistry::connections_[DisplayRegistry::kMaxDisplays];
+
+EGLDisplay DisplayRegistry::GetDisplay(EGLNativeDisplayType native_display) {
+ // Check to see if a display already exists for this native_display. If so,
+ // return it, otherwise create a new one and return that.
+ for (int i = 0; i < num_connections_; ++i) {
+ if (connections_[i].native_display == native_display) {
+ return reinterpret_cast<EGLDisplay>(&connections_[i]);
+ }
+ }
+
+ // If the platform-specific implementation does not accept the specified
+ // |native_display|, return in error.
+ if (!DisplayImpl::IsValidNativeDisplayType(native_display)) {
+ return EGL_NO_DISPLAY;
+ } else {
+ // Create a new display connection (i.e. EGLDisplay), add it to our
+ // display mapping so it can be looked up later, and then return it.
+ SB_CHECK(num_connections_ < kMaxDisplays);
+ connections_[num_connections_].native_display = native_display;
+ connections_[num_connections_].display = NULL;
+ ++num_connections_;
+ return reinterpret_cast<EGLDisplay>(&connections_[num_connections_ - 1]);
+ }
+}
+
+bool DisplayRegistry::InitializeDisplay(EGLDisplay display) {
+ SB_DCHECK(Valid(display));
+ Connection* connection = reinterpret_cast<Connection*>(display);
+ if (!connection->display) {
+ nb::scoped_ptr<DisplayImpl> display_impl =
+ DisplayImpl::Create(connection->native_display);
+ // If the platform-specific glimp implementation rejected the native
+ // display, then we return false to indicate failure.
+ if (!display_impl) {
+ return false;
+ }
+
+ connection->display = new Display(display_impl.Pass());
+ }
+
+ return true;
+}
+
+void DisplayRegistry::TerminateDisplay(EGLDisplay display) {
+ SB_DCHECK(Valid(display));
+ Connection* connection = reinterpret_cast<Connection*>(display);
+
+ if (connection->display) {
+ delete connection->display;
+ connection->display = NULL;
+ }
+}
+
+bool DisplayRegistry::Valid(EGLDisplay display) {
+ Connection* connection = reinterpret_cast<Connection*>(display);
+ for (int i = 0; i < num_connections_; ++i) {
+ if (connection == &connections_[i]) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// This function will either return the Display object associated with the
+// given EGLDisplay, or else set the appropriate EGL error and then return
+// NULL.
+egl::Display* GetDisplayOrSetError(EGLDisplay egl_display) {
+ if (!egl::DisplayRegistry::Valid(egl_display)) {
+ egl::SetError(EGL_BAD_DISPLAY);
+ return NULL;
+ }
+ egl::Display* display = egl::DisplayRegistry::ToDisplay(egl_display);
+ if (!display) {
+ egl::SetError(EGL_NOT_INITIALIZED);
+ return NULL;
+ }
+
+ return display;
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/display_registry.h b/src/glimp/egl/display_registry.h
new file mode 100644
index 0000000..ff07ef1
--- /dev/null
+++ b/src/glimp/egl/display_registry.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_DISPLAY_REGISTRY_H_
+#define GLIMP_EGL_DISPLAY_REGISTRY_H_
+
+#include "glimp/egl/display.h"
+#include "starboard/log.h"
+
+namespace glimp {
+namespace egl {
+
+// Maintains a registry of EGLDisplays as well as mappings from
+// EGLNativeDisplayType to those EGLDisplays. Internally, an EGLDisplay is
+// represented as a DisplayRegistry::Connection object that has a possibly null
+// pointer to a Display object. The Display object will be initialized when
+// DisplayRegistry::InitializeDisplay() is called, after which it may be
+// retrieved and have methods called on it.
+class DisplayRegistry {
+ public:
+ // Looks up the mapping from EGLNativeDisplayType to EGLDisplay, or creates
+ // one if it doesn't already exist, and returns the EGLDisplay associated
+ // with it. No failures will be reported by this method, it is
+ // InitializeDisplay() that will ultimately have the platform check
+ // whether the native display is valid or not.
+ static EGLDisplay GetDisplay(EGLNativeDisplayType native_display);
+
+ // Construct the Display object, if it has not yet been initialized already.
+ // This method can fail if the native display associated with the EGLDisplay
+ // is rejected by the platform. Returns true if the display is already
+ // initialized or successfully initialized, otherwise returns false.
+ static bool InitializeDisplay(EGLDisplay display);
+
+ // Terminates the display if it is initialized, otherwise it does nothing.
+ static void TerminateDisplay(EGLDisplay display);
+
+ // Returns true if the given |display| is valid, which will be true if it
+ // was at some point previously returned by GetDisplay() and false otherwise.
+ static bool Valid(EGLDisplay display);
+
+ // Returns the Display object associated with the given [valid] EGLDisplay
+ // object, or NULL if it is not initialized.
+ static Display* ToDisplay(EGLDisplay display) {
+ SB_DCHECK(Valid(display));
+ return reinterpret_cast<Connection*>(display)->display;
+ }
+
+ private:
+ // A Connection is the internal type of a EGLDisplay handle. It
+ // maintains a mapping from EGLNativeDisplayType to a (possibly null if it
+ // hasn't yet been eglInitialize()d) Display object.
+ struct Connection {
+ EGLNativeDisplayType native_display;
+ Display* display;
+ };
+
+ static const int kMaxDisplays = 10;
+
+ // The number of display connections currently active.
+ static int num_connections_;
+
+ // The mapping from native type to possibly initialized connection.
+ static Connection connections_[kMaxDisplays];
+};
+
+// This function will either return the Display object associated with the
+// given EGLDisplay, or else set the appropriate EGL error and then return
+// NULL.
+egl::Display* GetDisplayOrSetError(EGLDisplay egl_display);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_DISPLAY_REGISTRY_H_
diff --git a/src/glimp/egl/error.cc b/src/glimp/egl/error.cc
new file mode 100644
index 0000000..b18a34d
--- /dev/null
+++ b/src/glimp/egl/error.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/error.h"
+
+#include "starboard/once.h"
+#include "starboard/thread.h"
+
+namespace glimp {
+namespace egl {
+
+namespace {
+SbOnceControl s_error_once_control = SB_ONCE_INITIALIZER;
+SbThreadLocalKey s_error_tls_key = kSbThreadLocalKeyInvalid;
+
+void InitializeError() {
+ s_error_tls_key = SbThreadCreateLocalKey(NULL);
+}
+} // namespace
+
+EGLint GetError() {
+ SbOnce(&s_error_once_control, &InitializeError);
+ void* local_value = SbThreadGetLocalValue(s_error_tls_key);
+ if (local_value == NULL) {
+ // The EGL error has never been set. In this case, return EGL_SUCCESS as
+ // that is the initial value for eglGetError().
+ // Note that NULL or 0 are not valid EGL error codes.
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglGetError.xhtml
+ return EGL_SUCCESS;
+ }
+ return static_cast<EGLint>(reinterpret_cast<uintptr_t>(local_value));
+}
+
+void SetError(EGLint error) {
+ SbOnce(&s_error_once_control, &InitializeError);
+ SbThreadSetLocalValue(s_error_tls_key, reinterpret_cast<void*>(error));
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/error.h b/src/glimp/egl/error.h
new file mode 100644
index 0000000..51df122
--- /dev/null
+++ b/src/glimp/egl/error.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_ERROR_H_
+#define GLIMP_EGL_ERROR_H_
+
+#include <EGL/egl.h>
+
+namespace glimp {
+namespace egl {
+
+// Implements support for getting and setting the thread local EGL error
+// value.
+// https://www.khronos.org/registry/egl/sdk/docs/man/html/eglGetError.xhtml
+
+// Returns the current thread local error code.
+EGLint GetError();
+
+// Sets the current thread local error code.
+void SetError(EGLint error);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_ERROR_H_
diff --git a/src/glimp/egl/get_proc_address_impl.h b/src/glimp/egl/get_proc_address_impl.h
new file mode 100644
index 0000000..5ff61c6
--- /dev/null
+++ b/src/glimp/egl/get_proc_address_impl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2016 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_GET_PROC_ADDRESS_IMPL_H_
+#define GLIMP_EGL_GET_PROC_ADDRESS_IMPL_H_
+
+namespace glimp {
+namespace egl {
+
+typedef void (*MustCastToProperFunctionPointerType)(void);
+
+// Calls to eglGetProcAddress() that are unhandled by platform-independent
+// glimp code are forwarded to this platform-specific call, so that different
+// platforms can implement custom extensions. This function should return
+// a function pointer to the requested function upon success, and return NULL
+// if the requested function is not available.
+MustCastToProperFunctionPointerType GetProcAddressImpl(const char* procname);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_GET_PROC_ADDRESS_IMPL_H_
diff --git a/src/glimp/egl/scoped_egl_lock.cc b/src/glimp/egl/scoped_egl_lock.cc
new file mode 100644
index 0000000..4d8f546
--- /dev/null
+++ b/src/glimp/egl/scoped_egl_lock.cc
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/scoped_egl_lock.h"
+
+namespace glimp {
+namespace egl {
+
+SbMutex ScopedEGLLock::mutex_ = SB_MUTEX_INITIALIZER;
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/scoped_egl_lock.h b/src/glimp/egl/scoped_egl_lock.h
new file mode 100644
index 0000000..10f6628
--- /dev/null
+++ b/src/glimp/egl/scoped_egl_lock.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_SCOPED_EGL_LOCK_H_
+#define GLIMP_EGL_SCOPED_EGL_LOCK_H_
+
+#include "starboard/mutex.h"
+
+namespace glimp {
+namespace egl {
+
+// A helper class to enable easy locking of the glimp EGL global mutex.
+class ScopedEGLLock {
+ public:
+ ScopedEGLLock() { SbMutexAcquire(&mutex_); }
+ ~ScopedEGLLock() { SbMutexRelease(&mutex_); }
+
+ private:
+ static SbMutex mutex_;
+};
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_SCOPED_EGL_LOCK_H_
diff --git a/src/glimp/egl/surface.cc b/src/glimp/egl/surface.cc
new file mode 100644
index 0000000..3dc7a64
--- /dev/null
+++ b/src/glimp/egl/surface.cc
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 "glimp/egl/surface.h"
+
+#include "glimp/egl/error.h"
+#include "glimp/gles/context.h"
+#include "starboard/log.h"
+
+namespace glimp {
+namespace egl {
+
+Surface::Surface(nb::scoped_ptr<SurfaceImpl> surface_impl)
+ : surface_impl_(surface_impl.Pass()), is_bound_to_texture_(false) {}
+
+int Surface::GetWidth() const {
+ return surface_impl_->GetWidth();
+}
+
+int Surface::GetHeight() const {
+ return surface_impl_->GetHeight();
+}
+
+EGLint Surface::GetTextureFormat() const {
+ return EGL_TEXTURE_RGBA;
+}
+
+EGLint Surface::GetTextureTarget() const {
+ return EGL_TEXTURE_2D;
+}
+
+EGLBoolean Surface::QuerySurface(EGLint attribute, EGLint* value) {
+ switch (attribute) {
+ case EGL_HEIGHT: {
+ *value = GetHeight();
+ return true;
+ }
+
+ case EGL_WIDTH: {
+ *value = GetWidth();
+ return true;
+ }
+
+ case EGL_TEXTURE_FORMAT: {
+ // glimp only supports EGL_TEXTURE_RGBA.
+ *value = GetTextureFormat();
+ return true;
+ }
+
+ case EGL_TEXTURE_TARGET: {
+ // glimp only supports EGL_TEXTURE_2D.
+ *value = GetTextureTarget();
+ }
+
+ case EGL_CONFIG_ID:
+ case EGL_HORIZONTAL_RESOLUTION:
+ case EGL_LARGEST_PBUFFER:
+ case EGL_MIPMAP_LEVEL:
+ case EGL_MIPMAP_TEXTURE:
+ case EGL_MULTISAMPLE_RESOLVE:
+ case EGL_PIXEL_ASPECT_RATIO:
+ case EGL_RENDER_BUFFER:
+ case EGL_SWAP_BEHAVIOR:
+ case EGL_VERTICAL_RESOLUTION: {
+ SB_NOTIMPLEMENTED();
+ } // Fall through to default on purpose.
+
+ default:
+ SetError(EGL_BAD_ATTRIBUTE);
+ return false;
+ }
+
+ return true;
+}
+
+EGLBoolean Surface::BindTexImage(EGLint buffer) {
+ if (buffer != EGL_BACK_BUFFER) {
+ SetError(EGL_BAD_MATCH);
+ return false;
+ }
+
+ if (is_bound_to_texture_) {
+ SetError(EGL_BAD_ACCESS);
+ return false;
+ }
+
+ if (GetTextureTarget() == EGL_NO_TEXTURE) {
+ SetError(EGL_BAD_MATCH);
+ return false;
+ }
+ if (GetTextureTarget() != EGL_TEXTURE_2D) {
+ SB_NOTIMPLEMENTED() << "glimp does not support binding anything other than "
+ "EGL_TEXTURE_2D.";
+ SetError(EGL_BAD_MATCH);
+ return false;
+ }
+
+ // When this method is called, we should bind to the currently bound active
+ // texture in the current GL context.
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglBindTexImage.xhtml
+ gles::Context* current_context = gles::Context::GetTLSCurrentContext();
+ if (current_context == NULL) {
+ SB_DLOG(WARNING)
+ << "No GL ES context current during call to eglBindTexImage().";
+ // This error is non-specified behavior, but seems reasonable.
+ SetError(EGL_BAD_CONTEXT);
+ return false;
+ }
+
+ is_bound_to_texture_ = current_context->BindTextureToEGLSurface(this);
+ return is_bound_to_texture_;
+}
+
+EGLBoolean Surface::ReleaseTexImage(EGLint buffer) {
+ if (buffer != EGL_BACK_BUFFER) {
+ SetError(EGL_BAD_MATCH);
+ return false;
+ }
+
+ if (!is_bound_to_texture_) {
+ // Nothing to do if the surface is not already bound.
+ return true;
+ }
+
+ gles::Context* current_context = gles::Context::GetTLSCurrentContext();
+ if (current_context == NULL) {
+ SB_DLOG(WARNING)
+ << "No GL ES context current during call to eglReleaseTexImage().";
+ // This error is non-specified behavior, but seems reasonable.
+ SetError(EGL_BAD_CONTEXT);
+ return false;
+ }
+
+ if (current_context->ReleaseTextureFromEGLSurface(this)) {
+ is_bound_to_texture_ = false;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+namespace {
+bool AttributeKeyAndValueAreValid(int key, int value) {
+ switch (key) {
+ // First deal with the trivial keys where all values are valid.
+ case EGL_WIDTH:
+ case EGL_HEIGHT: {
+ return true;
+ }
+
+ case EGL_TEXTURE_TARGET: {
+ return value == EGL_TEXTURE_2D;
+ }
+
+ case EGL_TEXTURE_FORMAT: {
+ return value == EGL_TEXTURE_RGBA;
+ }
+ }
+
+ // If the switch statement didn't catch the key, this is an unknown
+ // key.
+ // TODO: glimp doesn't support all values yet, and will return false for keys
+ // that it doesn't support.
+ return false;
+}
+} // namespace
+
+bool ValidateSurfaceAttribList(const AttribMap& attribs) {
+ for (AttribMap::const_iterator iter = attribs.begin(); iter != attribs.end();
+ ++iter) {
+ if (!AttributeKeyAndValueAreValid(iter->first, iter->second)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+EGLSurface ToEGLSurface(Surface* surface) {
+ return reinterpret_cast<EGLSurface>(surface);
+}
+
+Surface* FromEGLSurface(EGLSurface surface) {
+ return reinterpret_cast<Surface*>(surface);
+}
+
+} // namespace egl
+} // namespace glimp
diff --git a/src/glimp/egl/surface.h b/src/glimp/egl/surface.h
new file mode 100644
index 0000000..dd26f2d
--- /dev/null
+++ b/src/glimp/egl/surface.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_SURFACE_H_
+#define GLIMP_EGL_SURFACE_H_
+
+#include <EGL/egl.h>
+
+#include <map>
+
+#include "glimp/egl/attrib_map.h"
+#include "glimp/egl/surface_impl.h"
+#include "nb/scoped_ptr.h"
+
+namespace glimp {
+namespace egl {
+
+class Surface {
+ public:
+ explicit Surface(nb::scoped_ptr<SurfaceImpl> surface_impl);
+
+ int GetWidth() const;
+ int GetHeight() const;
+
+ EGLint GetTextureFormat() const;
+ EGLint GetTextureTarget() const;
+
+ EGLBoolean QuerySurface(EGLint attribute, EGLint* value);
+ EGLBoolean BindTexImage(EGLint buffer);
+ EGLBoolean ReleaseTexImage(EGLint buffer);
+
+ bool is_bound_to_texture() const { return is_bound_to_texture_; }
+
+ SurfaceImpl* impl() const { return surface_impl_.get(); }
+
+ private:
+ nb::scoped_ptr<SurfaceImpl> surface_impl_;
+
+ // True if this surface is currently bound to a GL ES texture via
+ // eglBindTexImage().
+ bool is_bound_to_texture_;
+};
+
+bool ValidateSurfaceAttribList(const AttribMap& attribs);
+
+EGLSurface ToEGLSurface(Surface* surface);
+Surface* FromEGLSurface(EGLSurface surface);
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_SURFACE_H_
diff --git a/src/glimp/egl/surface_impl.h b/src/glimp/egl/surface_impl.h
new file mode 100644
index 0000000..ead72c4
--- /dev/null
+++ b/src/glimp/egl/surface_impl.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 GLIMP_EGL_SURFACE_IMPL_H_
+#define GLIMP_EGL_SURFACE_IMPL_H_
+
+#include <EGL/egl.h>
+
+namespace glimp {
+namespace egl {
+
+class SurfaceImpl {
+ public:
+ virtual ~SurfaceImpl() {}
+
+ // Returns a description of the underlying surface. This method will be
+ // referenced when functions like eglQuerySurface() are called.
+ // https://www.khronos.org/registry/egl/sdk/docs/man/html/eglQuerySurface.xhtml
+ virtual int GetWidth() const = 0;
+ virtual int GetHeight() const = 0;
+
+ private:
+};
+
+} // namespace egl
+} // namespace glimp
+
+#endif // GLIMP_EGL_SURFACE_IMPL_H_