Commit 59bf6885 authored by James Darpinian's avatar James Darpinian Committed by Commit Bot

Fix validation of transform feedback buffer sizes at draw time.

There were three problems:
1. We didn't multiply the number of vertices by the number of instances.
2. We didn't account for vertices written by previous draw calls.
3. We didn't round the vertex count down to the nearest number of whole
   primitives.

Fixes the WebGL 2 conformance test added here:
https://github.com/KhronosGroup/WebGL/pull/2604

Bug: 820639
Cq-Include-Trybots: master.tryserver.chromium.android:android_optional_gpu_tests_rel;master.tryserver.chromium.linux:linux_optional_gpu_tests_rel;master.tryserver.chromium.mac:mac_optional_gpu_tests_rel;master.tryserver.chromium.win:win_optional_gpu_tests_rel
Change-Id: I9566ad14aa6671eca127a1b7f68b73e6408acd10
Reviewed-on: https://chromium-review.googlesource.com/957743
Commit-Queue: James Darpinian <jdarpinian@chromium.org>
Reviewed-by: default avatarZhenyao Mo <zmo@chromium.org>
Reviewed-by: default avatarKenneth Russell <kbr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#543008}
parent 3f287816
...@@ -10580,12 +10580,11 @@ error::Error GLES2DecoderImpl::DoDrawArrays( ...@@ -10580,12 +10580,11 @@ error::Error GLES2DecoderImpl::DoDrawArrays(
return error::kNoError; return error::kNoError;
} }
if (!buffer_manager()->RequestBuffersAccess( if (!buffer_manager()->RequestBuffersAccess(
state_.GetErrorState(), state_.GetErrorState(), state_.bound_transform_feedback.get(),
state_.bound_transform_feedback.get(),
state_.current_program->GetTransformFeedbackVaryingSizes(), state_.current_program->GetTransformFeedbackVaryingSizes(),
count, state_.bound_transform_feedback->VerticesNeededForDraw(
function_name, mode, count, primcount),
"transformfeedback buffers")) { function_name, "transformfeedback buffers")) {
return error::kNoError; return error::kNoError;
} }
} }
...@@ -10634,6 +10633,10 @@ error::Error GLES2DecoderImpl::DoDrawArrays( ...@@ -10634,6 +10633,10 @@ error::Error GLES2DecoderImpl::DoDrawArrays(
} else { } else {
api()->glDrawArraysInstancedANGLEFn(mode, first, count, primcount); api()->glDrawArraysInstancedANGLEFn(mode, first, count, primcount);
} }
if (state_.bound_transform_feedback.get()) {
state_.bound_transform_feedback->OnVerticesDrawn(mode, count,
primcount);
}
if (textures_set) { if (textures_set) {
RestoreStateForTextures(); RestoreStateForTextures();
} }
......
...@@ -23,7 +23,8 @@ TransformFeedback::TransformFeedback(TransformFeedbackManager* manager, ...@@ -23,7 +23,8 @@ TransformFeedback::TransformFeedback(TransformFeedbackManager* manager,
has_been_bound_(false), has_been_bound_(false),
active_(false), active_(false),
paused_(false), paused_(false),
primitive_mode_(GL_NONE) { primitive_mode_(GL_NONE),
vertices_drawn_(0) {
DCHECK_LE(0u, client_id); DCHECK_LE(0u, client_id);
DCHECK_LT(0u, service_id); DCHECK_LT(0u, service_id);
} }
...@@ -75,6 +76,7 @@ void TransformFeedback::DoBeginTransformFeedback(GLenum primitive_mode) { ...@@ -75,6 +76,7 @@ void TransformFeedback::DoBeginTransformFeedback(GLenum primitive_mode) {
glBeginTransformFeedback(primitive_mode); glBeginTransformFeedback(primitive_mode);
active_ = true; active_ = true;
primitive_mode_ = primitive_mode; primitive_mode_ = primitive_mode;
vertices_drawn_ = 0;
} }
void TransformFeedback::DoEndTransformFeedback() { void TransformFeedback::DoEndTransformFeedback() {
...@@ -96,6 +98,33 @@ void TransformFeedback::DoResumeTransformFeedback() { ...@@ -96,6 +98,33 @@ void TransformFeedback::DoResumeTransformFeedback() {
paused_ = false; paused_ = false;
} }
GLsizei TransformFeedback::VerticesNeededForDraw(GLenum mode,
GLsizei count,
GLsizei primcount) const {
// Transform feedback only outputs complete primitives, so we need to round
// down to the nearest complete primitive before multiplying by the number of
// instances.
switch (mode) {
case GL_TRIANGLES:
return vertices_drawn_ + primcount * (count - count % 3);
case GL_LINES:
return vertices_drawn_ + primcount * (count - count % 2);
default:
NOTREACHED();
FALLTHROUGH;
case GL_POINTS:
return vertices_drawn_ + primcount * count;
}
}
void TransformFeedback::OnVerticesDrawn(GLenum mode,
GLsizei count,
GLsizei primcount) {
if (active_ && !paused_) {
vertices_drawn_ = VerticesNeededForDraw(mode, count, primcount);
}
}
TransformFeedbackManager::TransformFeedbackManager( TransformFeedbackManager::TransformFeedbackManager(
GLuint max_transform_feedback_separate_attribs, GLuint max_transform_feedback_separate_attribs,
bool needs_emulation) bool needs_emulation)
......
...@@ -61,6 +61,20 @@ class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost { ...@@ -61,6 +61,20 @@ class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost {
return primitive_mode_; return primitive_mode_;
} }
// Returns the number of vertices that this draw call will write to the
// transform feedback buffer, plus the number of vertices that were previously
// written since the last call to BeginTransformFeedback (because vertices are
// written starting just after the last vertex written by the previous draw).
// This is used to calculate whether there is enough space in the transform
// feedback buffers.
GLsizei VerticesNeededForDraw(GLenum mode,
GLsizei count,
GLsizei primcount) const;
// This must be called every time a transform feedback draw happens to keep
// track of how many vertices have been written to the transform feedback
// buffers.
void OnVerticesDrawn(GLenum mode, GLsizei count, GLsizei primcount);
private: private:
~TransformFeedback() override; ~TransformFeedback() override;
...@@ -76,6 +90,7 @@ class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost { ...@@ -76,6 +90,7 @@ class GPU_GLES2_EXPORT TransformFeedback : public IndexedBufferBindingHost {
bool paused_; bool paused_;
GLenum primitive_mode_; GLenum primitive_mode_;
GLsizei vertices_drawn_;
}; };
// This class keeps tracks of the transform feedbacks and their states. // This class keeps tracks of the transform feedbacks and their states.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment