| // Copyright 2018 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/multi_draw_manager.h" |
| |
| #include <algorithm> |
| |
| #include "base/logging.h" |
| #include "base/numerics/checked_math.h" |
| |
| namespace gpu { |
| namespace gles2 { |
| |
| MultiDrawManager::ResultData::ResultData() = default; |
| MultiDrawManager::ResultData::~ResultData() = default; |
| |
| MultiDrawManager::ResultData::ResultData(ResultData&& rhs) |
| : draw_function(rhs.draw_function), |
| drawcount(rhs.drawcount), |
| mode(rhs.mode), |
| type(rhs.type), |
| firsts(std::move(rhs.firsts)), |
| counts(std::move(rhs.counts)), |
| offsets(std::move(rhs.offsets)), |
| indices(std::move(rhs.indices)), |
| instance_counts(std::move(rhs.instance_counts)), |
| basevertices(std::move(rhs.basevertices)), |
| baseinstances(std::move(rhs.baseinstances)) {} |
| |
| MultiDrawManager::ResultData& MultiDrawManager::ResultData::operator=( |
| ResultData&& rhs) { |
| if (&rhs == this) { |
| return *this; |
| } |
| draw_function = rhs.draw_function; |
| drawcount = rhs.drawcount; |
| mode = rhs.mode; |
| type = rhs.type; |
| std::swap(firsts, rhs.firsts); |
| std::swap(counts, rhs.counts); |
| std::swap(offsets, rhs.offsets); |
| std::swap(indices, rhs.indices); |
| std::swap(instance_counts, rhs.instance_counts); |
| std::swap(basevertices, rhs.basevertices); |
| std::swap(baseinstances, rhs.baseinstances); |
| return *this; |
| } |
| |
| MultiDrawManager::MultiDrawManager(IndexStorageType index_type) |
| : draw_state_(DrawState::End), |
| current_draw_offset_(0), |
| index_type_(index_type), |
| result_() {} |
| |
| bool MultiDrawManager::Begin(GLsizei drawcount) { |
| if (draw_state_ != DrawState::End) { |
| return false; |
| } |
| result_.drawcount = drawcount; |
| current_draw_offset_ = 0; |
| draw_state_ = DrawState::Begin; |
| return true; |
| } |
| |
| bool MultiDrawManager::End(ResultData* result) { |
| DCHECK(result); |
| if (draw_state_ != DrawState::Draw || |
| current_draw_offset_ != result_.drawcount) { |
| return false; |
| } |
| draw_state_ = DrawState::End; |
| *result = std::move(result_); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawArrays(GLenum mode, |
| const GLint* firsts, |
| const GLsizei* counts, |
| GLsizei drawcount) { |
| if (!EnsureDrawArraysFunction(DrawFunction::DrawArrays, mode, drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, firsts, counts, nullptr, nullptr, nullptr, |
| nullptr); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawArraysInstanced(GLenum mode, |
| const GLint* firsts, |
| const GLsizei* counts, |
| const GLsizei* instance_counts, |
| GLsizei drawcount) { |
| if (!EnsureDrawArraysFunction(DrawFunction::DrawArraysInstanced, mode, |
| drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, firsts, counts, nullptr, instance_counts, nullptr, |
| nullptr); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawArraysInstancedBaseInstance( |
| GLenum mode, |
| const GLint* firsts, |
| const GLsizei* counts, |
| const GLsizei* instance_counts, |
| const GLuint* baseinstances, |
| GLsizei drawcount) { |
| if (!EnsureDrawArraysFunction(DrawFunction::DrawArraysInstancedBaseInstance, |
| mode, drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, firsts, counts, nullptr, instance_counts, nullptr, |
| baseinstances); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawElements(GLenum mode, |
| const GLsizei* counts, |
| GLenum type, |
| const GLsizei* offsets, |
| GLsizei drawcount) { |
| if (!EnsureDrawElementsFunction(DrawFunction::DrawElements, mode, type, |
| drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, nullptr, counts, offsets, nullptr, nullptr, |
| nullptr); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawElementsInstanced( |
| GLenum mode, |
| const GLsizei* counts, |
| GLenum type, |
| const GLsizei* offsets, |
| const GLsizei* instance_counts, |
| GLsizei drawcount) { |
| if (!EnsureDrawElementsFunction(DrawFunction::DrawElementsInstanced, mode, |
| type, drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, nullptr, counts, offsets, instance_counts, |
| nullptr, nullptr); |
| return true; |
| } |
| |
| bool MultiDrawManager::MultiDrawElementsInstancedBaseVertexBaseInstance( |
| GLenum mode, |
| const GLsizei* counts, |
| GLenum type, |
| const GLsizei* offsets, |
| const GLsizei* instance_counts, |
| const GLint* basevertices, |
| const GLuint* baseinstances, |
| GLsizei drawcount) { |
| if (!EnsureDrawElementsFunction( |
| DrawFunction::DrawElementsInstancedBaseVertexBaseInstance, mode, type, |
| drawcount)) { |
| return false; |
| } |
| CopyArraysHelper(drawcount, nullptr, counts, offsets, instance_counts, |
| basevertices, baseinstances); |
| return true; |
| } |
| |
| void MultiDrawManager::ResizeArrays() { |
| switch (result_.draw_function) { |
| case DrawFunction::DrawArraysInstancedBaseInstance: |
| result_.baseinstances.resize(result_.drawcount); |
| FALLTHROUGH; |
| case DrawFunction::DrawArraysInstanced: |
| result_.instance_counts.resize(result_.drawcount); |
| FALLTHROUGH; |
| case DrawFunction::DrawArrays: |
| result_.firsts.resize(result_.drawcount); |
| result_.counts.resize(result_.drawcount); |
| break; |
| case DrawFunction::DrawElementsInstancedBaseVertexBaseInstance: |
| result_.basevertices.resize(result_.drawcount); |
| result_.baseinstances.resize(result_.drawcount); |
| FALLTHROUGH; |
| case DrawFunction::DrawElementsInstanced: |
| result_.instance_counts.resize(result_.drawcount); |
| FALLTHROUGH; |
| case DrawFunction::DrawElements: |
| result_.counts.resize(result_.drawcount); |
| switch (index_type_) { |
| case IndexStorageType::Offset: |
| result_.offsets.resize(result_.drawcount); |
| break; |
| case IndexStorageType::Pointer: |
| result_.indices.resize(result_.drawcount); |
| break; |
| } |
| break; |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| bool MultiDrawManager::ValidateDrawcount(GLsizei drawcount) const { |
| if (drawcount < 0) { |
| return false; |
| } |
| GLsizei new_offset; |
| if (!base::CheckAdd(current_draw_offset_, drawcount) |
| .AssignIfValid(&new_offset)) { |
| return false; |
| } |
| if (new_offset > result_.drawcount) { |
| return false; |
| } |
| return true; |
| } |
| |
| bool MultiDrawManager::EnsureDrawArraysFunction(DrawFunction draw_function, |
| GLenum mode, |
| GLsizei drawcount) { |
| if (!ValidateDrawcount(drawcount)) { |
| return false; |
| } |
| bool invalid_draw_state = draw_state_ == DrawState::End; |
| bool first_call = draw_state_ == DrawState::Begin; |
| bool enums_match = result_.mode == mode; |
| |
| if (invalid_draw_state || (!first_call && !enums_match)) { |
| return false; |
| } |
| if (first_call) { |
| draw_state_ = DrawState::Draw; |
| result_.draw_function = draw_function; |
| result_.mode = mode; |
| ResizeArrays(); |
| } |
| return true; |
| } |
| |
| bool MultiDrawManager::EnsureDrawElementsFunction(DrawFunction draw_function, |
| GLenum mode, |
| GLenum type, |
| GLsizei drawcount) { |
| if (!ValidateDrawcount(drawcount)) { |
| return false; |
| } |
| bool invalid_draw_state = draw_state_ == DrawState::End; |
| bool first_call = draw_state_ == DrawState::Begin; |
| bool enums_match = result_.mode == mode && result_.type == type; |
| |
| if (invalid_draw_state || (!first_call && !enums_match)) { |
| return false; |
| } |
| if (first_call) { |
| draw_state_ = DrawState::Draw; |
| result_.draw_function = draw_function; |
| result_.mode = mode; |
| result_.type = type; |
| ResizeArrays(); |
| } |
| return true; |
| } |
| |
| void MultiDrawManager::CopyArraysHelper(GLsizei drawcount, |
| const GLint* firsts, |
| const GLsizei* counts, |
| const GLsizei* offsets, |
| const GLsizei* instance_counts, |
| const GLint* basevertices, |
| const GLuint* baseinstances) { |
| if (firsts) { |
| std::copy(firsts, firsts + drawcount, |
| &result_.firsts[current_draw_offset_]); |
| } |
| |
| if (counts) { |
| std::copy(counts, counts + drawcount, |
| &result_.counts[current_draw_offset_]); |
| } |
| |
| if (instance_counts) { |
| std::copy(instance_counts, instance_counts + drawcount, |
| &result_.instance_counts[current_draw_offset_]); |
| } |
| |
| if (basevertices) { |
| std::copy(basevertices, basevertices + drawcount, |
| &result_.basevertices[current_draw_offset_]); |
| } |
| |
| if (baseinstances) { |
| std::copy(baseinstances, baseinstances + drawcount, |
| &result_.baseinstances[current_draw_offset_]); |
| } |
| |
| if (offsets) { |
| switch (index_type_) { |
| case IndexStorageType::Offset: |
| std::copy(offsets, offsets + drawcount, |
| &result_.offsets[current_draw_offset_]); |
| break; |
| case IndexStorageType::Pointer: |
| std::transform( |
| offsets, offsets + drawcount, |
| &result_.indices[current_draw_offset_], [](uint32_t offset) { |
| return reinterpret_cast<void*>(static_cast<intptr_t>(offset)); |
| }); |
| break; |
| } |
| } |
| |
| current_draw_offset_ += drawcount; |
| } |
| |
| } // namespace gles2 |
| } // namespace gpu |