blob: 4a33437e4d21eac0df7e6e6a9afaeb6460ad335b [file] [log] [blame]
/*
* 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