Fix edge case where an empty struct could be generated in an ESSL 1.0 shader. Include _maskThreshold and _doubleSided in ESSL 1.0 shaders. Add GL_OES_standard_derivatives extension to ESSL 1.0 shaders. According to gpuinfo.org, this has 96% device coverage and supports both Mali-400 and Adreno (TM) 304. Remove 3D sampler support from ESSL 1.0 shaders. This extension is only supported by 62% of devices. Change filagui material to a FL0 material.
241 lines
7.9 KiB
C++
241 lines
7.9 KiB
C++
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "private/filament/BufferInterfaceBlock.h"
|
|
|
|
#include <utils/Panic.h>
|
|
#include <utils/compiler.h>
|
|
|
|
#include <utility>
|
|
|
|
using namespace utils;
|
|
|
|
namespace filament {
|
|
|
|
BufferInterfaceBlock::Builder::Builder() noexcept = default;
|
|
BufferInterfaceBlock::Builder::~Builder() noexcept = default;
|
|
|
|
BufferInterfaceBlock::Builder&
|
|
BufferInterfaceBlock::Builder::name(std::string_view interfaceBlockName) {
|
|
mName = { interfaceBlockName.data(), interfaceBlockName.size() };
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::alignment(
|
|
BufferInterfaceBlock::Alignment alignment) {
|
|
mAlignment = alignment;
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::target(
|
|
BufferInterfaceBlock::Target target) {
|
|
mTarget = target;
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::qualifier(
|
|
BufferInterfaceBlock::Qualifier qualifier) {
|
|
mQualifiers |= uint8_t(qualifier);
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::add(
|
|
std::initializer_list<InterfaceBlockEntry> list) {
|
|
mEntries.reserve(mEntries.size() + list.size());
|
|
for (auto const& item : list) {
|
|
mEntries.push_back({
|
|
{ item.name.data(), item.name.size() },
|
|
0, uint8_t(item.stride), item.type, item.size > 0, item.size, item.precision, item.minFeatureLevel,
|
|
{ item.structName.data(), item.structName.size() },
|
|
{ item.sizeName.data(), item.sizeName.size() }
|
|
});
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock::Builder& BufferInterfaceBlock::Builder::addVariableSizedArray(
|
|
BufferInterfaceBlock::InterfaceBlockEntry const& item) {
|
|
mHasVariableSizeArray = true;
|
|
mEntries.push_back({
|
|
{ item.name.data(), item.name.size() },
|
|
0, uint8_t(item.stride), item.type, true, 0, item.precision, item.minFeatureLevel,
|
|
{ item.structName.data(), item.structName.size() },
|
|
{ item.sizeName.data(), item.sizeName.size() }
|
|
});
|
|
return *this;
|
|
}
|
|
|
|
BufferInterfaceBlock BufferInterfaceBlock::Builder::build() {
|
|
// look for the first variable-size array
|
|
auto pos = std::find_if(mEntries.begin(), mEntries.end(),
|
|
[](FieldInfo const& item) -> bool {
|
|
return item.isArray && !item.size;
|
|
});
|
|
|
|
// if there is one, check it's the last entry
|
|
ASSERT_PRECONDITION(pos == mEntries.end() || pos == mEntries.end() - 1,
|
|
"the variable-size array must be the last entry");
|
|
|
|
// if we have a variable size array, we can't be a UBO
|
|
ASSERT_PRECONDITION(pos == mEntries.end() || mTarget == Target::SSBO,
|
|
"variable size arrays not supported for UBOs");
|
|
|
|
// std430 not available for UBOs
|
|
ASSERT_PRECONDITION(mAlignment == Alignment::std140 || mTarget == Target::SSBO,
|
|
"UBOs must use std140");
|
|
|
|
return BufferInterfaceBlock(*this);
|
|
}
|
|
|
|
bool BufferInterfaceBlock::Builder::hasVariableSizeArray() const {
|
|
return mHasVariableSizeArray;
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
|
|
BufferInterfaceBlock::BufferInterfaceBlock() = default;
|
|
BufferInterfaceBlock::BufferInterfaceBlock(BufferInterfaceBlock&& rhs) noexcept = default;
|
|
BufferInterfaceBlock& BufferInterfaceBlock::operator=(BufferInterfaceBlock&& rhs) noexcept = default;
|
|
BufferInterfaceBlock::~BufferInterfaceBlock() noexcept = default;
|
|
|
|
BufferInterfaceBlock::BufferInterfaceBlock(Builder const& builder) noexcept
|
|
: mName(builder.mName),
|
|
mFieldInfoList(builder.mEntries.size()),
|
|
mAlignment(builder.mAlignment),
|
|
mTarget(builder.mTarget)
|
|
{
|
|
auto& infoMap = mInfoMap;
|
|
infoMap.reserve(builder.mEntries.size());
|
|
|
|
auto& uniformsInfoList = mFieldInfoList;
|
|
|
|
uint32_t i = 0;
|
|
uint16_t offset = 0;
|
|
for (auto const& e : builder.mEntries) {
|
|
size_t alignment = baseAlignmentForType(e.type);
|
|
size_t stride = strideForType(e.type, e.stride);
|
|
|
|
if (e.isArray) { // this is an array
|
|
if (builder.mAlignment == Alignment::std140) {
|
|
// in std140 arrays are aligned to float4
|
|
alignment = 4;
|
|
}
|
|
// the stride of an array is always rounded to its alignment (which is POT)
|
|
stride = (stride + alignment - 1) & ~(alignment - 1);
|
|
}
|
|
|
|
// calculate the offset for this uniform
|
|
size_t padding = (alignment - (offset % alignment)) % alignment;
|
|
offset += padding;
|
|
|
|
FieldInfo& info = uniformsInfoList[i];
|
|
info = { e.name, offset, uint8_t(stride), e.type, e.isArray, e.size,
|
|
e.precision, e.minFeatureLevel, e.structName, e.sizeName };
|
|
|
|
// record this uniform info
|
|
infoMap[{ info.name.data(), info.name.size() }] = i;
|
|
|
|
// advance offset to next slot
|
|
offset += stride * std::max(1u, e.size);
|
|
++i;
|
|
}
|
|
|
|
// round size to the next multiple of 4 and convert to bytes
|
|
mSize = sizeof(uint32_t) * ((offset + 3) & ~3);
|
|
}
|
|
|
|
ssize_t BufferInterfaceBlock::getFieldOffset(std::string_view name, size_t index) const {
|
|
auto const* info = getFieldInfo(name);
|
|
assert_invariant(info);
|
|
return (ssize_t)info->getBufferOffset(index);
|
|
}
|
|
|
|
BufferInterfaceBlock::FieldInfo const* BufferInterfaceBlock::getFieldInfo(
|
|
std::string_view name) const {
|
|
auto pos = mInfoMap.find(name);
|
|
ASSERT_PRECONDITION(pos != mInfoMap.end(),
|
|
"uniform named \"%.*s\" not found", name.size(), name.data());
|
|
return &mFieldInfoList[pos->second];
|
|
}
|
|
|
|
bool BufferInterfaceBlock::isEmptyForFeatureLevel(
|
|
backend::FeatureLevel featureLevel) const noexcept {
|
|
return std::all_of(mFieldInfoList.begin(), mFieldInfoList.end(),
|
|
[featureLevel](auto const &info) {
|
|
return featureLevel < info.minFeatureLevel;
|
|
});
|
|
}
|
|
|
|
uint8_t UTILS_NOINLINE BufferInterfaceBlock::baseAlignmentForType(BufferInterfaceBlock::Type type) noexcept {
|
|
switch (type) {
|
|
case Type::BOOL:
|
|
case Type::FLOAT:
|
|
case Type::INT:
|
|
case Type::UINT:
|
|
return 1;
|
|
case Type::BOOL2:
|
|
case Type::FLOAT2:
|
|
case Type::INT2:
|
|
case Type::UINT2:
|
|
return 2;
|
|
case Type::BOOL3:
|
|
case Type::BOOL4:
|
|
case Type::FLOAT3:
|
|
case Type::FLOAT4:
|
|
case Type::INT3:
|
|
case Type::INT4:
|
|
case Type::UINT3:
|
|
case Type::UINT4:
|
|
case Type::MAT3:
|
|
case Type::MAT4:
|
|
case Type::STRUCT:
|
|
return 4;
|
|
}
|
|
}
|
|
|
|
uint8_t UTILS_NOINLINE BufferInterfaceBlock::strideForType(BufferInterfaceBlock::Type type, uint32_t stride) noexcept {
|
|
switch (type) {
|
|
case Type::BOOL:
|
|
case Type::INT:
|
|
case Type::UINT:
|
|
case Type::FLOAT:
|
|
return 1;
|
|
case Type::BOOL2:
|
|
case Type::INT2:
|
|
case Type::UINT2:
|
|
case Type::FLOAT2:
|
|
return 2;
|
|
case Type::BOOL3:
|
|
case Type::INT3:
|
|
case Type::UINT3:
|
|
case Type::FLOAT3:
|
|
return 3;
|
|
case Type::BOOL4:
|
|
case Type::INT4:
|
|
case Type::UINT4:
|
|
case Type::FLOAT4:
|
|
return 4;
|
|
case Type::MAT3:
|
|
return 12;
|
|
case Type::MAT4:
|
|
return 16;
|
|
case Type::STRUCT:
|
|
return stride;
|
|
}
|
|
}
|
|
|
|
} // namespace filament
|