blob: 72c18d23b5ca4bb2316540f05bafe0cf66dae937 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/service/error_state.h"
#include <stdint.h>
#include <string>
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/logger.h"
#include "ui/gl/gl_bindings.h"
namespace gpu {
namespace gles2 {
class ErrorStateImpl : public ErrorState {
public:
explicit ErrorStateImpl(ErrorStateClient* client, Logger* logger);
~ErrorStateImpl() override;
uint32_t GetGLError() override;
void SetGLError(const char* filename,
int line,
unsigned int error,
const char* function_name,
const char* msg) override;
void SetGLErrorInvalidEnum(const char* filename,
int line,
const char* function_name,
unsigned int value,
const char* label) override;
void SetGLErrorInvalidParami(const char* filename,
int line,
unsigned int error,
const char* function_name,
unsigned int pname,
int param) override;
void SetGLErrorInvalidParamf(const char* filename,
int line,
unsigned int error,
const char* function_name,
unsigned int pname,
float param) override;
unsigned int PeekGLError(const char* filename,
int line,
const char* function_name) override;
void CopyRealGLErrorsToWrapper(const char* filename,
int line,
const char* function_name) override;
void ClearRealGLErrors(const char* filename,
int line,
const char* function_name) override;
private:
GLenum GetErrorHandleContextLoss();
// The last error message set.
std::string last_error_;
// Current GL error bits.
uint32_t error_bits_;
ErrorStateClient* client_;
Logger* logger_;
DISALLOW_COPY_AND_ASSIGN(ErrorStateImpl);
};
ErrorState::ErrorState() = default;
ErrorState::~ErrorState() = default;
ErrorState* ErrorState::Create(ErrorStateClient* client, Logger* logger) {
return new ErrorStateImpl(client, logger);
}
ErrorStateImpl::ErrorStateImpl(ErrorStateClient* client, Logger* logger)
: error_bits_(0), client_(client), logger_(logger) {}
ErrorStateImpl::~ErrorStateImpl() = default;
uint32_t ErrorStateImpl::GetGLError() {
// Check the GL error first, then our wrapped error.
GLenum error = GetErrorHandleContextLoss();
if (error == GL_NO_ERROR && error_bits_ != 0) {
for (uint32_t mask = 1; mask != 0; mask = mask << 1) {
if ((error_bits_ & mask) != 0) {
error = GLES2Util::GLErrorBitToGLError(mask);
break;
}
}
}
if (error != GL_NO_ERROR) {
// There was an error, clear the corresponding wrapped error.
error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
}
return error;
}
GLenum ErrorStateImpl::GetErrorHandleContextLoss() {
GLenum error = glGetError();
if (error == GL_CONTEXT_LOST_KHR) {
client_->OnContextLostError();
// Do not expose GL_CONTEXT_LOST_KHR, as the version of the robustness
// extension that introduces the error is not exposed by the command
// buffer.
error = GL_NO_ERROR;
}
return error;
}
unsigned int ErrorStateImpl::PeekGLError(
const char* filename, int line, const char* function_name) {
GLenum error = GetErrorHandleContextLoss();
if (error != GL_NO_ERROR) {
SetGLError(filename, line, error, function_name, "");
}
return error;
}
void ErrorStateImpl::SetGLError(
const char* filename,
int line,
unsigned int error,
const char* function_name,
const char* msg) {
if (msg) {
last_error_ = msg;
logger_->LogMessage(
filename, line,
std::string("GL ERROR :") +
GLES2Util::GetStringEnum(error) + " : " +
function_name + ": " + msg);
}
error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
if (error == GL_OUT_OF_MEMORY)
client_->OnOutOfMemoryError();
}
void ErrorStateImpl::SetGLErrorInvalidEnum(
const char* filename,
int line,
const char* function_name,
unsigned int value,
const char* label) {
SetGLError(filename, line, GL_INVALID_ENUM, function_name,
(std::string(label) + " was " +
GLES2Util::GetStringEnum(value)).c_str());
}
void ErrorStateImpl::SetGLErrorInvalidParami(
const char* filename,
int line,
unsigned int error,
const char* function_name,
unsigned int pname, int param) {
if (error == GL_INVALID_ENUM) {
SetGLError(
filename, line, GL_INVALID_ENUM, function_name,
(std::string("trying to set ") +
GLES2Util::GetStringEnum(pname) + " to " +
GLES2Util::GetStringEnum(param)).c_str());
} else {
SetGLError(
filename, line, error, function_name,
(std::string("trying to set ") +
GLES2Util::GetStringEnum(pname) + " to " +
base::IntToString(param)).c_str());
}
}
void ErrorStateImpl::SetGLErrorInvalidParamf(
const char* filename,
int line,
unsigned int error,
const char* function_name,
unsigned int pname, float param) {
SetGLError(
filename, line, error, function_name,
(std::string("trying to set ") +
GLES2Util::GetStringEnum(pname) + " to " +
base::StringPrintf("%G", param)).c_str());
}
void ErrorStateImpl::CopyRealGLErrorsToWrapper(
const char* filename, int line, const char* function_name) {
GLenum error;
while ((error = GetErrorHandleContextLoss()) != GL_NO_ERROR) {
SetGLError(filename, line, error, function_name,
"<- error from previous GL command");
}
}
void ErrorStateImpl::ClearRealGLErrors(
const char* filename, int line, const char* function_name) {
// Clears and logs all current gl errors.
GLenum error;
while ((error = glGetError()) != GL_NO_ERROR) {
if (error != GL_CONTEXT_LOST_KHR && error != GL_OUT_OF_MEMORY) {
// GL_OUT_OF_MEMORY can legally happen on lost device.
logger_->LogMessage(
filename, line,
std::string("GL ERROR :") +
GLES2Util::GetStringEnum(error) + " : " +
function_name + ": was unhandled");
NOTREACHED() << "GL error " << error << " was unhandled.";
}
}
}
} // namespace gles2
} // namespace gpu