| /* |
| * Copyright 2023 The Cobalt Authors. All Rights Reserved. |
| * 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 <utility> |
| |
| #include "glimp/egl/error.h" |
| #include "glimp/gles/context.h" |
| #include "starboard/common/log.h" |
| |
| namespace glimp { |
| namespace egl { |
| |
| Surface::Surface(std::unique_ptr<SurfaceImpl> surface_impl) |
| : surface_impl_(std::move(surface_impl)), 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 |