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(ErrorStateClient* client, 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 SetGLErrorInvalidParami(
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  virtual void SetGLErrorInvalidParamf(
44      const char* filename,
45      int line,
46      unsigned int error,
47      const char* function_name,
48      unsigned int pname,
49      float param) OVERRIDE;
50
51  virtual unsigned int PeekGLError(
52      const char* filename, int line, const char* function_name) OVERRIDE;
53
54  virtual void CopyRealGLErrorsToWrapper(
55      const char* filename, int line, const char* function_name) OVERRIDE;
56
57  virtual void ClearRealGLErrors(
58      const char* filename, int line, const char* function_name) OVERRIDE;
59
60 private:
61  // The last error message set.
62  std::string last_error_;
63  // Current GL error bits.
64  uint32 error_bits_;
65
66  ErrorStateClient* client_;
67  Logger* logger_;
68
69  DISALLOW_COPY_AND_ASSIGN(ErrorStateImpl);
70};
71
72ErrorState::ErrorState() {}
73
74ErrorState::~ErrorState() {}
75
76ErrorState* ErrorState::Create(ErrorStateClient* client, Logger* logger) {
77  return new ErrorStateImpl(client, logger);
78}
79
80ErrorStateImpl::ErrorStateImpl(ErrorStateClient* client, Logger* logger)
81    : error_bits_(0), client_(client), logger_(logger) {}
82
83ErrorStateImpl::~ErrorStateImpl() {}
84
85uint32 ErrorStateImpl::GetGLError() {
86  // Check the GL error first, then our wrapped error.
87  GLenum error = glGetError();
88  if (error == GL_NO_ERROR && error_bits_ != 0) {
89    for (uint32 mask = 1; mask != 0; mask = mask << 1) {
90      if ((error_bits_ & mask) != 0) {
91        error = GLES2Util::GLErrorBitToGLError(mask);
92        break;
93      }
94    }
95  }
96
97  if (error != GL_NO_ERROR) {
98    // There was an error, clear the corresponding wrapped error.
99    error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
100  }
101  return error;
102}
103
104unsigned int ErrorStateImpl::PeekGLError(
105    const char* filename, int line, const char* function_name) {
106  GLenum error = glGetError();
107  if (error != GL_NO_ERROR) {
108    SetGLError(filename, line, error, function_name, "");
109  }
110  return error;
111}
112
113void ErrorStateImpl::SetGLError(
114    const char* filename,
115    int line,
116    unsigned int error,
117    const char* function_name,
118    const char* msg) {
119  if (msg) {
120    last_error_ = msg;
121    logger_->LogMessage(
122        filename, line,
123        std::string("GL ERROR :") +
124        GLES2Util::GetStringEnum(error) + " : " +
125        function_name + ": " + msg);
126  }
127  error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
128  if (error == GL_OUT_OF_MEMORY)
129    client_->OnOutOfMemoryError();
130}
131
132void ErrorStateImpl::SetGLErrorInvalidEnum(
133    const char* filename,
134    int line,
135    const char* function_name,
136    unsigned int value,
137    const char* label) {
138  SetGLError(filename, line, GL_INVALID_ENUM, function_name,
139             (std::string(label) + " was " +
140             GLES2Util::GetStringEnum(value)).c_str());
141}
142
143void ErrorStateImpl::SetGLErrorInvalidParami(
144    const char* filename,
145    int line,
146    unsigned int error,
147    const char* function_name,
148    unsigned int pname, int param) {
149  if (error == GL_INVALID_ENUM) {
150    SetGLError(
151        filename, line, GL_INVALID_ENUM, function_name,
152        (std::string("trying to set ") +
153         GLES2Util::GetStringEnum(pname) + " to " +
154         GLES2Util::GetStringEnum(param)).c_str());
155  } else {
156    SetGLError(
157        filename, line, error, function_name,
158        (std::string("trying to set ") +
159         GLES2Util::GetStringEnum(pname) + " to " +
160         base::StringPrintf("%d", param)).c_str());
161  }
162}
163
164void ErrorStateImpl::SetGLErrorInvalidParamf(
165    const char* filename,
166    int line,
167    unsigned int error,
168    const char* function_name,
169    unsigned int pname, float param) {
170  SetGLError(
171      filename, line, error, function_name,
172      (std::string("trying to set ") +
173       GLES2Util::GetStringEnum(pname) + " to " +
174       base::StringPrintf("%G", param)).c_str());
175}
176
177void ErrorStateImpl::CopyRealGLErrorsToWrapper(
178    const char* filename, int line, const char* function_name) {
179  GLenum error;
180  while ((error = glGetError()) != GL_NO_ERROR) {
181    SetGLError(filename, line, error, function_name,
182               "<- error from previous GL command");
183  }
184}
185
186void ErrorStateImpl::ClearRealGLErrors(
187    const char* filename, int line, const char* function_name) {
188  // Clears and logs all current gl errors.
189  GLenum error;
190  while ((error = glGetError()) != GL_NO_ERROR) {
191    if (error != GL_OUT_OF_MEMORY) {
192      // GL_OUT_OF_MEMORY can legally happen on lost device.
193      logger_->LogMessage(
194          filename, line,
195          std::string("GL ERROR :") +
196          GLES2Util::GetStringEnum(error) + " : " +
197          function_name + ": was unhandled");
198      NOTREACHED() << "GL error " << error << " was unhandled.";
199    }
200  }
201}
202
203}  // namespace gles2
204}  // namespace gpu
205
206