1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gpu/command_buffer/service/error_state.h"
6
7#include <string>
8
9#include "base/strings/stringprintf.h"
10#include "gpu/command_buffer/common/gles2_cmd_utils.h"
11#include "gpu/command_buffer/service/logger.h"
12#include "ui/gl/gl_bindings.h"
13
14namespace gpu {
15namespace gles2 {
16
17class ErrorStateImpl : public ErrorState {
18 public:
19  explicit ErrorStateImpl(Logger* logger);
20  virtual ~ErrorStateImpl();
21
22  virtual uint32 GetGLError() OVERRIDE;
23
24  virtual void SetGLError(
25      const char* filename,
26      int line,
27      unsigned int error,
28      const char* function_name,
29      const char* msg) OVERRIDE;
30  virtual void SetGLErrorInvalidEnum(
31      const char* filename,
32      int line,
33      const char* function_name,
34      unsigned int value,
35      const char* label) OVERRIDE;
36  virtual void SetGLErrorInvalidParam(
37      const char* filename,
38      int line,
39      unsigned int error,
40      const char* function_name,
41      unsigned int pname,
42      int param) OVERRIDE;
43
44  virtual unsigned int PeekGLError(
45      const char* filename, int line, const char* function_name) OVERRIDE;
46
47  virtual void CopyRealGLErrorsToWrapper(
48      const char* filename, int line, const char* function_name) OVERRIDE;
49
50  virtual void ClearRealGLErrors(
51      const char* filename, int line, const char* function_name) OVERRIDE;
52
53 private:
54  // The last error message set.
55  std::string last_error_;
56  // Current GL error bits.
57  uint32 error_bits_;
58
59  Logger* logger_;
60
61  DISALLOW_COPY_AND_ASSIGN(ErrorStateImpl);
62};
63
64ErrorState::ErrorState() {}
65
66ErrorState::~ErrorState() {}
67
68ErrorState* ErrorState::Create(Logger* logger) {
69  return new ErrorStateImpl(logger);
70}
71
72ErrorStateImpl::ErrorStateImpl(Logger* logger)
73    : error_bits_(0),
74      logger_(logger) {}
75
76ErrorStateImpl::~ErrorStateImpl() {}
77
78uint32 ErrorStateImpl::GetGLError() {
79  // Check the GL error first, then our wrapped error.
80  GLenum error = glGetError();
81  if (error == GL_NO_ERROR && error_bits_ != 0) {
82    for (uint32 mask = 1; mask != 0; mask = mask << 1) {
83      if ((error_bits_ & mask) != 0) {
84        error = GLES2Util::GLErrorBitToGLError(mask);
85        break;
86      }
87    }
88  }
89
90  if (error != GL_NO_ERROR) {
91    // There was an error, clear the corresponding wrapped error.
92    error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
93  }
94  return error;
95}
96
97unsigned int ErrorStateImpl::PeekGLError(
98    const char* filename, int line, const char* function_name) {
99  GLenum error = glGetError();
100  if (error != GL_NO_ERROR) {
101    SetGLError(filename, line, error, function_name, "");
102  }
103  return error;
104}
105
106void ErrorStateImpl::SetGLError(
107    const char* filename,
108    int line,
109    unsigned int error,
110    const char* function_name,
111    const char* msg) {
112  if (msg) {
113    last_error_ = msg;
114    logger_->LogMessage(
115        filename, line,
116        std::string("GL ERROR :") +
117        GLES2Util::GetStringEnum(error) + " : " +
118        function_name + ": " + msg);
119  }
120  error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
121}
122
123void ErrorStateImpl::SetGLErrorInvalidEnum(
124    const char* filename,
125    int line,
126    const char* function_name,
127    unsigned int value,
128    const char* label) {
129  SetGLError(filename, line, GL_INVALID_ENUM, function_name,
130             (std::string(label) + " was " +
131             GLES2Util::GetStringEnum(value)).c_str());
132}
133
134void ErrorStateImpl::SetGLErrorInvalidParam(
135    const char* filename,
136    int line,
137    unsigned int error,
138    const char* function_name,
139    unsigned int pname, int param) {
140  if (error == GL_INVALID_ENUM) {
141    SetGLError(
142        filename, line, GL_INVALID_ENUM, function_name,
143        (std::string("trying to set ") +
144         GLES2Util::GetStringEnum(pname) + " to " +
145         GLES2Util::GetStringEnum(param)).c_str());
146  } else {
147    SetGLError(
148        filename, line, error, function_name,
149        (std::string("trying to set ") +
150         GLES2Util::GetStringEnum(pname) + " to " +
151         base::StringPrintf("%d", param)).c_str());
152  }
153}
154
155void ErrorStateImpl::CopyRealGLErrorsToWrapper(
156    const char* filename, int line, const char* function_name) {
157  GLenum error;
158  while ((error = glGetError()) != GL_NO_ERROR) {
159    SetGLError(filename, line, error, function_name,
160               "<- error from previous GL command");
161  }
162}
163
164void ErrorStateImpl::ClearRealGLErrors(
165    const char* filename, int line, const char* function_name) {
166  // Clears and logs all current gl errors.
167  GLenum error;
168  while ((error = glGetError()) != GL_NO_ERROR) {
169    if (error != GL_OUT_OF_MEMORY) {
170      // GL_OUT_OF_MEMORY can legally happen on lost device.
171      logger_->LogMessage(
172          filename, line,
173          std::string("GL ERROR :") +
174          GLES2Util::GetStringEnum(error) + " : " +
175          function_name + ": was unhandled");
176      NOTREACHED() << "GL error " << error << " was unhandled.";
177    }
178  }
179}
180
181}  // namespace gles2
182}  // namespace gpu
183
184