Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8c6189d53 | ||
|
|
940cc8caef | ||
|
|
c57fdebdf0 | ||
|
|
059d902ca3 | ||
|
|
6df0089950 | ||
|
|
d1f41a91ec | ||
|
|
a1b7cd51b4 | ||
|
|
6a3f885e46 | ||
|
|
18a9d0762b | ||
|
|
eb1060381a | ||
|
|
b270bae970 | ||
|
|
b54be98731 | ||
|
|
0e1e0d5664 | ||
|
|
0b17ea1804 | ||
|
|
06580cc6f9 | ||
|
|
bb63996182 | ||
|
|
83e1a676c5 | ||
|
|
21fa6b5805 | ||
|
|
62e8666eee | ||
|
|
ca9ff1642f | ||
|
|
ace66343ce | ||
|
|
4bf8828df1 | ||
|
|
7307518e44 | ||
|
|
8890b8eb2a | ||
|
|
a7d274e5bd | ||
|
|
bfdc50ee76 | ||
|
|
b0ccfb2c2a | ||
|
|
f191d7a0b7 | ||
|
|
0a0156a484 | ||
|
|
e48a8d3ff4 | ||
|
|
811ee522e0 | ||
|
|
7cb8ae0c0d | ||
|
|
dbb48c4e4e | ||
|
|
8cc658e5be | ||
|
|
785461a26c | ||
|
|
7bf0e49a91 | ||
|
|
55627c3896 | ||
|
|
1987384dec | ||
|
|
3b617a6733 | ||
|
|
963e1f633b | ||
|
|
6eec277428 | ||
|
|
dbd59bd119 | ||
|
|
3dc15a4f96 | ||
|
|
4900fee536 | ||
|
|
34df1b4a16 | ||
|
|
f5560deab7 | ||
|
|
307a32f9a0 | ||
|
|
7bb4991edd | ||
|
|
f5720663c2 | ||
|
|
53927e175e | ||
|
|
20a68e1e9d | ||
|
|
c7668fd43e | ||
|
|
eb7f950322 | ||
|
|
80609ee974 | ||
|
|
28630ff109 | ||
|
|
b049f7d273 | ||
|
|
f6ccf2c368 | ||
|
|
27a0010b6e | ||
|
|
b06b9cc7a2 | ||
|
|
943f91cf0b | ||
|
|
bd8caa5294 | ||
|
|
3ddf349ca1 | ||
|
|
d707d241fc | ||
|
|
aa5d2cf9d7 | ||
|
|
decf41a3cb | ||
|
|
d7dc4f2143 | ||
|
|
fbd94e4237 | ||
|
|
48cc8f4c8c | ||
|
|
e1721012d8 | ||
|
|
5af01bef9f |
53 changed files with 1845 additions and 235 deletions
5
externals/ffmpeg/CMakeLists.txt
vendored
5
externals/ffmpeg/CMakeLists.txt
vendored
|
|
@ -59,6 +59,11 @@ endif()
|
|||
if (PLATFORM_PS4 OR PLATFORM_MANAGARM)
|
||||
# Doesn't support VA-API, don't go thru the embarrassment of trying to enable it
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
|
||||
elseif (ANDROID)
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-mediacodec
|
||||
--enable-jni
|
||||
)
|
||||
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING AND NOT ANDROID)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBVA libva)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ if (ARCHITECTURE_arm64)
|
|||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||
endif()
|
||||
|
||||
target_link_libraries(yuzu-android PRIVATE OpenSSL::SSL cpp-jwt::cpp-jwt)
|
||||
target_link_libraries(yuzu-android PRIVATE ${FFmpeg_LIBRARIES} OpenSSL::SSL cpp-jwt::cpp-jwt)
|
||||
if (ENABLE_UPDATE_CHECKER)
|
||||
target_compile_definitions(yuzu-android PUBLIC ENABLE_UPDATE_CHECKER)
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@
|
|||
#include <frontend_common/content_manager.h>
|
||||
#include <jni.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavcodec/jni.h>
|
||||
}
|
||||
|
||||
#include "common/android/multiplayer/multiplayer.h"
|
||||
#include "common/android/android_common.h"
|
||||
#include "common/android/id_cache.h"
|
||||
|
|
@ -680,6 +684,13 @@ const char* fallback_cpu_detection() {
|
|||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
jint InitFFmpegOnLoad(JavaVM* vm) {
|
||||
av_jni_set_java_vm(vm, nullptr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env, jobject instance,
|
||||
|
|
|
|||
|
|
@ -427,8 +427,11 @@ namespace Common::Android {
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
jint InitFFmpegOnLoad(JavaVM *vm);
|
||||
|
||||
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
s_java_vm = vm;
|
||||
InitFFmpegOnLoad(vm);
|
||||
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
|
|
|||
|
|
@ -403,6 +403,9 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
|||
if (info.uses_sampled_1d) {
|
||||
ctx.AddCapability(spv::Capability::Sampled1D);
|
||||
}
|
||||
if (info.uses_image_1d) {
|
||||
ctx.AddCapability(spv::Capability::Image1D);
|
||||
}
|
||||
if (info.uses_sparse_residency) {
|
||||
ctx.AddCapability(spv::Capability::SparseResidency);
|
||||
}
|
||||
|
|
@ -432,7 +435,7 @@ void SetupCapabilities(const Profile& profile, const Info& info, EmitContext& ct
|
|||
}
|
||||
if ((info.uses_subgroup_vote || info.uses_subgroup_invocation_id ||
|
||||
info.uses_subgroup_shuffles) &&
|
||||
profile.support_vote) {
|
||||
profile.support_vote && profile.SupportsSubgroupStage(ctx.stage)) {
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniformBallot);
|
||||
ctx.AddCapability(spv::Capability::GroupNonUniformShuffle);
|
||||
if (!profile.warp_size_potentially_larger_than_guest) {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,8 @@ void EmitGetIndirectBranchVariable(EmitContext&) {
|
|||
}
|
||||
|
||||
Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8 &&
|
||||
ctx.profile.support_uniform_and_storage_buffer_8bit) {
|
||||
const Id load{GetCbuf(ctx, ctx.U8, &UniformDefinitions::U8, sizeof(u8), binding, offset,
|
||||
ctx.load_const_func_u8)};
|
||||
return ctx.OpUConvert(ctx.U32[1], load);
|
||||
|
|
@ -219,7 +220,8 @@ Id EmitGetCbufU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& of
|
|||
}
|
||||
|
||||
Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int8 &&
|
||||
ctx.profile.support_uniform_and_storage_buffer_8bit) {
|
||||
const Id load{GetCbuf(ctx, ctx.S8, &UniformDefinitions::S8, sizeof(s8), binding, offset,
|
||||
ctx.load_const_func_u8)};
|
||||
return ctx.OpSConvert(ctx.U32[1], load);
|
||||
|
|
@ -236,7 +238,8 @@ Id EmitGetCbufS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& of
|
|||
}
|
||||
|
||||
Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16 &&
|
||||
ctx.profile.support_uniform_and_storage_buffer_16bit) {
|
||||
const Id load{GetCbuf(ctx, ctx.U16, &UniformDefinitions::U16, sizeof(u16), binding, offset,
|
||||
ctx.load_const_func_u16)};
|
||||
return ctx.OpUConvert(ctx.U32[1], load);
|
||||
|
|
@ -253,7 +256,8 @@ Id EmitGetCbufU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& o
|
|||
}
|
||||
|
||||
Id EmitGetCbufS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16) {
|
||||
if (ctx.profile.support_descriptor_aliasing && ctx.profile.support_int16 &&
|
||||
ctx.profile.support_uniform_and_storage_buffer_16bit) {
|
||||
const Id load{GetCbuf(ctx, ctx.S16, &UniformDefinitions::S16, sizeof(s16), binding, offset,
|
||||
ctx.load_const_func_u16)};
|
||||
return ctx.OpSConvert(ctx.U32[1], load);
|
||||
|
|
|
|||
|
|
@ -260,6 +260,13 @@ bool IsTextureMsaa(EmitContext& ctx, const IR::TextureInstInfo& info) {
|
|||
return ctx.textures.at(info.descriptor_index).is_multisample;
|
||||
}
|
||||
|
||||
bool IsTextureInteger(EmitContext& ctx, const IR::TextureInstInfo& info) {
|
||||
if (info.type == TextureType::Buffer) {
|
||||
return false;
|
||||
}
|
||||
return ctx.textures.at(info.descriptor_index).is_integer;
|
||||
}
|
||||
|
||||
Id Decorate(EmitContext& ctx, IR::Inst* inst, Id sample) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
if (info.relaxed_precision != 0) {
|
||||
|
|
@ -480,11 +487,14 @@ Id EmitBoundImageWrite(EmitContext&) {
|
|||
Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id bias_lc, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
Id color;
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
const ImageOperands operands(ctx, info.has_bias != 0, false, info.has_lod_clamp != 0,
|
||||
bias_lc, offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleImplicitLod,
|
||||
&EmitContext::OpImageSampleImplicitLod, ctx, inst, ctx.F32[4],
|
||||
color = Emit(&EmitContext::OpImageSparseSampleImplicitLod,
|
||||
&EmitContext::OpImageSampleImplicitLod, ctx, inst, result_type,
|
||||
Texture(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
|
||||
} else {
|
||||
// We can't use implicit lods on non-fragment stages on SPIR-V. Maxwell hardware behaves as
|
||||
|
|
@ -492,26 +502,29 @@ Id EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value&
|
|||
// derivatives
|
||||
const Id lod{ctx.Const(0.0f)};
|
||||
const ImageOperands operands(ctx, false, true, info.has_lod_clamp != 0, lod, offset);
|
||||
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
|
||||
color = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
|
||||
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
|
||||
}
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
|
||||
}
|
||||
|
||||
Id EmitImageSampleExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id lod, const IR::Value& offset) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
const ImageOperands operands(ctx, false, true, false, lod, offset);
|
||||
|
||||
Id result = Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
|
||||
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
|
||||
#ifdef __ANDROID__
|
||||
if (Settings::values.fix_bloom_effects.GetValue()) {
|
||||
if (!is_integer && Settings::values.fix_bloom_effects.GetValue()) {
|
||||
result = ctx.OpVectorTimesScalar(ctx.F32[4], result, ctx.Const(0.98f));
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], result) : result;
|
||||
}
|
||||
|
||||
Id EmitImageSampleDrefImplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index,
|
||||
|
|
@ -547,30 +560,39 @@ Id EmitImageSampleDrefExplicitLod(EmitContext& ctx, IR::Inst* inst, const IR::Va
|
|||
Id EmitImageGather(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
const IR::Value& offset, const IR::Value& offset2) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
const ImageOperands operands(ctx, offset, offset2);
|
||||
if (ctx.profile.need_gather_subpixel_offset) {
|
||||
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
|
||||
}
|
||||
return Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
|
||||
ctx.F32[4], Texture(ctx, info, index), coords, ctx.Const(info.gather_component),
|
||||
operands.MaskOptional(), operands.Span());
|
||||
const Id color{Emit(&EmitContext::OpImageSparseGather, &EmitContext::OpImageGather, ctx, inst,
|
||||
result_type, Texture(ctx, info, index), coords,
|
||||
ctx.Const(info.gather_component), operands.MaskOptional(),
|
||||
operands.Span())};
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
|
||||
}
|
||||
|
||||
Id EmitImageGatherDref(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
const IR::Value& offset, const IR::Value& offset2, Id dref) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
const ImageOperands operands(ctx, offset, offset2);
|
||||
if (ctx.profile.need_gather_subpixel_offset) {
|
||||
coords = ImageGatherSubpixelOffset(ctx, info, TextureImage(ctx, info, index), coords);
|
||||
}
|
||||
return Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather, ctx, inst,
|
||||
ctx.F32[4], Texture(ctx, info, index), coords, dref, operands.MaskOptional(),
|
||||
operands.Span());
|
||||
const Id color{Emit(&EmitContext::OpImageSparseDrefGather, &EmitContext::OpImageDrefGather,
|
||||
ctx, inst, result_type, Texture(ctx, info, index), coords, dref,
|
||||
operands.MaskOptional(), operands.Span())};
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
|
||||
}
|
||||
|
||||
Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id offset,
|
||||
Id lod, Id ms) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
AddOffsetToCoordinates(ctx, info, coords, offset);
|
||||
if (info.type == TextureType::Buffer) {
|
||||
lod = Id{};
|
||||
|
|
@ -580,8 +602,10 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
|
|||
lod = Id{};
|
||||
}
|
||||
const ImageOperands operands(lod, ms);
|
||||
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
|
||||
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
|
||||
const Id color{Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst,
|
||||
result_type, TextureImage(ctx, info, index), coords,
|
||||
operands.MaskOptional(), operands.Span())};
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
|
||||
}
|
||||
|
||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
|
||||
|
|
@ -626,14 +650,17 @@ Id EmitImageQueryLod(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, I
|
|||
Id EmitImageGradient(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords,
|
||||
Id derivatives, const IR::Value& offset, Id lod_clamp) {
|
||||
const auto info{inst->Flags<IR::TextureInstInfo>()};
|
||||
const bool is_integer{IsTextureInteger(ctx, info)};
|
||||
const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
|
||||
const auto operands = info.num_derivatives == 3
|
||||
? ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
|
||||
ctx.Def(offset), {}, lod_clamp)
|
||||
: ImageOperands(ctx, info.has_lod_clamp != 0, derivatives,
|
||||
info.num_derivatives, offset, lod_clamp);
|
||||
return Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, ctx.F32[4],
|
||||
Texture(ctx, info, index), coords, operands.Mask(), operands.Span());
|
||||
const Id color{Emit(&EmitContext::OpImageSparseSampleExplicitLod,
|
||||
&EmitContext::OpImageSampleExplicitLod, ctx, inst, result_type,
|
||||
Texture(ctx, info, index), coords, operands.Mask(), operands.Span())};
|
||||
return is_integer ? ctx.OpBitcast(ctx.F32[4], color) : color;
|
||||
}
|
||||
|
||||
Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords) {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -10,7 +13,14 @@ Id SubgroupScope(EmitContext& ctx) {
|
|||
return ctx.Const(static_cast<u32>(spv::Scope::Subgroup));
|
||||
}
|
||||
|
||||
bool StageSupportsSubgroups(EmitContext& ctx) {
|
||||
return ctx.profile.SupportsSubgroupStage(ctx.stage);
|
||||
}
|
||||
|
||||
Id GetThreadId(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.u32_zero_value;
|
||||
}
|
||||
return ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id);
|
||||
}
|
||||
|
||||
|
|
@ -68,6 +78,9 @@ Id GetMaxThreadId(EmitContext& ctx, Id thread_id, Id clamp, Id segmentation_mask
|
|||
}
|
||||
|
||||
Id SelectValue(EmitContext& ctx, Id in_range, Id value, Id src_thread_id) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return value;
|
||||
}
|
||||
return ctx.OpSelect(
|
||||
ctx.U32[1], in_range,
|
||||
ctx.OpGroupNonUniformShuffle(ctx.U32[1], SubgroupScope(ctx), value, src_thread_id), value);
|
||||
|
|
@ -89,6 +102,9 @@ Id EmitLaneId(EmitContext& ctx) {
|
|||
}
|
||||
|
||||
Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return pred;
|
||||
}
|
||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||
return ctx.OpGroupNonUniformAll(ctx.U1, SubgroupScope(ctx), pred);
|
||||
}
|
||||
|
|
@ -102,6 +118,9 @@ Id EmitVoteAll(EmitContext& ctx, Id pred) {
|
|||
}
|
||||
|
||||
Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return pred;
|
||||
}
|
||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||
return ctx.OpGroupNonUniformAny(ctx.U1, SubgroupScope(ctx), pred);
|
||||
}
|
||||
|
|
@ -115,6 +134,9 @@ Id EmitVoteAny(EmitContext& ctx, Id pred) {
|
|||
}
|
||||
|
||||
Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.true_value;
|
||||
}
|
||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||
return ctx.OpGroupNonUniformAllEqual(ctx.U1, SubgroupScope(ctx), pred);
|
||||
}
|
||||
|
|
@ -129,6 +151,9 @@ Id EmitVoteEqual(EmitContext& ctx, Id pred) {
|
|||
}
|
||||
|
||||
Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.OpSelect(ctx.U32[1], pred, ctx.Const(1u), ctx.u32_zero_value);
|
||||
}
|
||||
const Id ballot{ctx.OpGroupNonUniformBallot(ctx.U32[4], SubgroupScope(ctx), pred)};
|
||||
if (!ctx.profile.warp_size_potentially_larger_than_guest) {
|
||||
return ctx.OpCompositeExtract(ctx.U32[1], ballot, 0U);
|
||||
|
|
@ -137,22 +162,37 @@ Id EmitSubgroupBallot(EmitContext& ctx, Id pred) {
|
|||
}
|
||||
|
||||
Id EmitSubgroupEqMask(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.Const(1u);
|
||||
}
|
||||
return LoadMask(ctx, ctx.subgroup_mask_eq);
|
||||
}
|
||||
|
||||
Id EmitSubgroupLtMask(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.u32_zero_value;
|
||||
}
|
||||
return LoadMask(ctx, ctx.subgroup_mask_lt);
|
||||
}
|
||||
|
||||
Id EmitSubgroupLeMask(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.Const(1u);
|
||||
}
|
||||
return LoadMask(ctx, ctx.subgroup_mask_le);
|
||||
}
|
||||
|
||||
Id EmitSubgroupGtMask(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.u32_zero_value;
|
||||
}
|
||||
return LoadMask(ctx, ctx.subgroup_mask_gt);
|
||||
}
|
||||
|
||||
Id EmitSubgroupGeMask(EmitContext& ctx) {
|
||||
if (!StageSupportsSubgroups(ctx)) {
|
||||
return ctx.Const(1u);
|
||||
}
|
||||
return LoadMask(ctx, ctx.subgroup_mask_ge);
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +262,7 @@ Id EmitShuffleButterfly(EmitContext& ctx, IR::Inst* inst, Id value, Id index, Id
|
|||
|
||||
Id EmitFSwizzleAdd(EmitContext& ctx, Id op_a, Id op_b, Id swizzle) {
|
||||
const Id three{ctx.Const(3U)};
|
||||
Id mask{ctx.OpLoad(ctx.U32[1], ctx.subgroup_local_invocation_id)};
|
||||
Id mask{GetThreadId(ctx)};
|
||||
mask = ctx.OpBitwiseAnd(ctx.U32[1], mask, three);
|
||||
mask = ctx.OpShiftLeftLogical(ctx.U32[1], mask, ctx.Const(1U));
|
||||
mask = ctx.OpShiftRightLogical(ctx.U32[1], swizzle, mask);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ enum class Operation {
|
|||
|
||||
Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
|
||||
const spv::ImageFormat format{spv::ImageFormat::Unknown};
|
||||
const Id type{ctx.F32[1]};
|
||||
const Id type{desc.is_integer ? ctx.U32[1] : ctx.F32[1]};
|
||||
const bool depth{desc.is_depth};
|
||||
const bool ms{desc.is_multisample};
|
||||
switch (desc.type) {
|
||||
|
|
@ -1126,7 +1126,7 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
|
|||
}
|
||||
IR::Type types{info.used_constant_buffer_types | info.used_indirect_cbuf_types};
|
||||
if (True(types & IR::Type::U8)) {
|
||||
if (profile.support_int8) {
|
||||
if (profile.support_int8 && profile.support_uniform_and_storage_buffer_8bit) {
|
||||
DefineConstBuffers(*this, info, &UniformDefinitions::U8, binding, U8, 'u', sizeof(u8));
|
||||
DefineConstBuffers(*this, info, &UniformDefinitions::S8, binding, S8, 's', sizeof(s8));
|
||||
} else {
|
||||
|
|
@ -1134,7 +1134,7 @@ void EmitContext::DefineConstantBuffers(const Info& info, u32& binding) {
|
|||
}
|
||||
}
|
||||
if (True(types & IR::Type::U16)) {
|
||||
if (profile.support_int16) {
|
||||
if (profile.support_int16 && profile.support_uniform_and_storage_buffer_16bit) {
|
||||
DefineConstBuffers(*this, info, &UniformDefinitions::U16, binding, U16, 'u',
|
||||
sizeof(u16));
|
||||
DefineConstBuffers(*this, info, &UniformDefinitions::S16, binding, S16, 's',
|
||||
|
|
@ -1196,10 +1196,18 @@ void EmitContext::DefineConstantBufferIndirectFunctions(const Info& info) {
|
|||
IR::Type types{info.used_indirect_cbuf_types};
|
||||
bool supports_aliasing = profile.support_descriptor_aliasing;
|
||||
if (supports_aliasing && True(types & IR::Type::U8)) {
|
||||
load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8);
|
||||
if (profile.support_int8 && profile.support_uniform_and_storage_buffer_8bit) {
|
||||
load_const_func_u8 = make_accessor(U8, &UniformDefinitions::U8);
|
||||
} else {
|
||||
types |= IR::Type::U32;
|
||||
}
|
||||
}
|
||||
if (supports_aliasing && True(types & IR::Type::U16)) {
|
||||
load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16);
|
||||
if (profile.support_int16 && profile.support_uniform_and_storage_buffer_16bit) {
|
||||
load_const_func_u16 = make_accessor(U16, &UniformDefinitions::U16);
|
||||
} else {
|
||||
types |= IR::Type::U32;
|
||||
}
|
||||
}
|
||||
if (supports_aliasing && True(types & IR::Type::F32)) {
|
||||
load_const_func_f32 = make_accessor(F32[1], &UniformDefinitions::F32);
|
||||
|
|
@ -1375,6 +1383,7 @@ void EmitContext::DefineTextures(const Info& info, u32& binding, u32& scaling_in
|
|||
.image_type = image_type,
|
||||
.count = desc.count,
|
||||
.is_multisample = desc.is_multisample,
|
||||
.is_integer = desc.is_integer,
|
||||
});
|
||||
if (profile.supported_spirv >= 0x00010400) {
|
||||
interfaces.push_back(id);
|
||||
|
|
@ -1438,7 +1447,7 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||
if (info.uses_is_helper_invocation) {
|
||||
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
|
||||
}
|
||||
if (info.uses_subgroup_mask) {
|
||||
if (info.uses_subgroup_mask && profile.SupportsSubgroupStage(stage)) {
|
||||
subgroup_mask_eq = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupEqMaskKHR);
|
||||
subgroup_mask_lt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLtMaskKHR);
|
||||
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
||||
|
|
@ -1452,9 +1461,10 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
|
||||
}
|
||||
}
|
||||
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
||||
(profile.warp_size_potentially_larger_than_guest &&
|
||||
(info.uses_subgroup_vote || info.uses_subgroup_mask))) {
|
||||
if ((info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
||||
(profile.warp_size_potentially_larger_than_guest &&
|
||||
(info.uses_subgroup_vote || info.uses_subgroup_mask))) &&
|
||||
profile.SupportsSubgroupStage(stage)) {
|
||||
AddCapability(spv::Capability::GroupNonUniform);
|
||||
subgroup_local_invocation_id =
|
||||
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ struct TextureDefinition {
|
|||
Id image_type;
|
||||
u32 count;
|
||||
bool is_multisample;
|
||||
bool is_integer;
|
||||
};
|
||||
|
||||
struct TextureBufferDefinition {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
|
@ -43,6 +46,10 @@ union TextureInstInfo {
|
|||
BitField<25, 2, u32> num_derivatives;
|
||||
BitField<27, 3, ImageFormat> image_format;
|
||||
BitField<30, 1, u32> ndv_is_active;
|
||||
/// Only meaningful for the sampled-texture family (ImageSampleImplicitLod, ImageFetch,
|
||||
/// ImageGather, etc.); unused/zero for storage-image opcodes, which carry their own
|
||||
/// is_integer via ImageDescriptor/ImageBufferDescriptor instead.
|
||||
BitField<31, 1, u32> is_integer;
|
||||
};
|
||||
static_assert(sizeof(TextureInstInfo) <= sizeof(u32));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
|
|
@ -569,6 +569,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||
case IR::Opcode::ImageRead: {
|
||||
const auto flags{inst.Flags<IR::TextureInstInfo>()};
|
||||
info.uses_typeless_image_reads |= flags.image_format == ImageFormat::Typeless;
|
||||
info.uses_image_1d |=
|
||||
flags.type == TextureType::Color1D || flags.type == TextureType::ColorArray1D;
|
||||
info.uses_sparse_residency |=
|
||||
inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr;
|
||||
break;
|
||||
|
|
@ -577,6 +579,8 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||
const auto flags{inst.Flags<IR::TextureInstInfo>()};
|
||||
info.uses_typeless_image_writes |= flags.image_format == ImageFormat::Typeless;
|
||||
info.uses_image_buffers |= flags.type == TextureType::Buffer;
|
||||
info.uses_image_1d |=
|
||||
flags.type == TextureType::Color1D || flags.type == TextureType::ColorArray1D;
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::SubgroupEqMask:
|
||||
|
|
@ -761,9 +765,13 @@ void VisitUsages(Info& info, IR::Inst& inst) {
|
|||
case IR::Opcode::ImageAtomicAnd32:
|
||||
case IR::Opcode::ImageAtomicOr32:
|
||||
case IR::Opcode::ImageAtomicXor32:
|
||||
case IR::Opcode::ImageAtomicExchange32:
|
||||
case IR::Opcode::ImageAtomicExchange32: {
|
||||
const auto flags{inst.Flags<IR::TextureInstInfo>()};
|
||||
info.uses_atomic_image_u32 = true;
|
||||
info.uses_image_1d |=
|
||||
flags.type == TextureType::Color1D || flags.type == TextureType::ColorArray1D;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,6 +562,7 @@ public:
|
|||
})};
|
||||
// TODO: Read this from TIC
|
||||
texture_descriptors[index].is_multisample |= desc.is_multisample;
|
||||
texture_descriptors[index].is_integer |= desc.is_integer;
|
||||
return index;
|
||||
}
|
||||
|
||||
|
|
@ -685,6 +686,21 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||
program.info.image_descriptors,
|
||||
};
|
||||
const u32 sampled_dynamic_cap = DynamicSampledTextureCap(program.info, host_info, DynamicSampledTextureArrayCount(to_replace));
|
||||
bool has_last_is_integer{false};
|
||||
u32 last_cbuf_index{};
|
||||
u32 last_cbuf_offset{};
|
||||
bool last_is_integer{false};
|
||||
const auto is_texture_pixel_format_integer{[&](const ConstBufferAddr& cbuf_addr) {
|
||||
if (has_last_is_integer && last_cbuf_index == cbuf_addr.index &&
|
||||
last_cbuf_offset == cbuf_addr.offset) {
|
||||
return last_is_integer;
|
||||
}
|
||||
last_is_integer = IsTexturePixelFormatIntegerCached(env, cbuf_addr);
|
||||
last_cbuf_index = cbuf_addr.index;
|
||||
last_cbuf_offset = cbuf_addr.offset;
|
||||
has_last_is_integer = true;
|
||||
return last_is_integer;
|
||||
}};
|
||||
for (TextureInst& texture_inst : to_replace) {
|
||||
// TODO: Handle arrays
|
||||
IR::Inst* const inst{texture_inst.inst};
|
||||
|
|
@ -749,7 +765,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||
}
|
||||
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
|
||||
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
|
||||
const bool is_integer{IsTexturePixelFormatIntegerCached(env, cbuf)};
|
||||
const bool is_integer{is_texture_pixel_format_integer(cbuf)};
|
||||
if (flags.type == TextureType::Buffer) {
|
||||
index = descriptors.Add(ImageBufferDescriptor{
|
||||
.format = flags.image_format,
|
||||
|
|
@ -791,10 +807,12 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||
});
|
||||
} else {
|
||||
count = std::min(count, sampled_dynamic_cap);
|
||||
const bool is_integer{is_texture_pixel_format_integer(cbuf)};
|
||||
index = descriptors.Add(TextureDescriptor{
|
||||
.type = flags.type,
|
||||
.is_depth = flags.is_depth != 0,
|
||||
.is_multisample = is_multisample,
|
||||
.is_integer = is_integer,
|
||||
.has_secondary = cbuf.has_secondary,
|
||||
.cbuf_index = cbuf.index,
|
||||
.cbuf_offset = cbuf.offset,
|
||||
|
|
@ -805,6 +823,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
|
|||
.count = count,
|
||||
.size_shift = size_shift,
|
||||
});
|
||||
flags.is_integer.Assign(is_integer ? 1 : 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,16 @@
|
|||
|
||||
namespace Shader {
|
||||
|
||||
enum class Stage : u32;
|
||||
|
||||
struct Profile {
|
||||
u32 supported_spirv{0x00010000};
|
||||
bool unified_descriptor_binding{};
|
||||
bool support_descriptor_aliasing{};
|
||||
bool support_int8{};
|
||||
bool support_uniform_and_storage_buffer_8bit{};
|
||||
bool support_int16{};
|
||||
bool support_uniform_and_storage_buffer_16bit{};
|
||||
bool support_int64{};
|
||||
bool support_vertex_instance_id{};
|
||||
bool support_float_controls{};
|
||||
|
|
@ -30,6 +34,7 @@ struct Profile {
|
|||
bool support_fp64_signed_zero_nan_preserve{};
|
||||
bool support_explicit_workgroup_layout{};
|
||||
bool support_vote{};
|
||||
u32 supported_subgroup_stages{0x7F};
|
||||
bool support_viewport_index_layer_non_geometry{};
|
||||
bool support_viewport_mask{};
|
||||
bool support_typeless_image_loads{};
|
||||
|
|
@ -93,6 +98,10 @@ struct Profile {
|
|||
|
||||
u64 min_ssbo_alignment{};
|
||||
u32 max_user_clip_distances{};
|
||||
|
||||
bool SupportsSubgroupStage(Stage stage) const {
|
||||
return (supported_subgroup_stages & (1u << static_cast<u32>(stage))) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Shader
|
||||
|
|
|
|||
|
|
@ -209,6 +209,7 @@ struct TextureDescriptor {
|
|||
TextureType type;
|
||||
bool is_depth;
|
||||
bool is_multisample;
|
||||
bool is_integer;
|
||||
bool has_secondary;
|
||||
u32 cbuf_index;
|
||||
u32 cbuf_offset;
|
||||
|
|
|
|||
|
|
@ -20,58 +20,54 @@ Decoder::Decoder(Host1x::Host1x& host1x_, s32 id_, const Host1x::NvdecCommon::Nv
|
|||
|
||||
Decoder::~Decoder() = default;
|
||||
|
||||
void Decoder::SetFrameDimensions(s32 width, s32 height) {
|
||||
if (width <= 0 || height <= 0) {
|
||||
frame_dimensions.reset();
|
||||
return;
|
||||
}
|
||||
frame_dimensions = FFmpeg::FrameDimensions{width, height};
|
||||
}
|
||||
|
||||
void Decoder::Decode() {
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto packet_data = ComposeFrame();
|
||||
// Send assembled bitstream to decoder.
|
||||
if (!decode_api.SendPacket(packet_data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only receive/store visible frames.
|
||||
if (vp9_hidden_frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Receive output frames from decoder.
|
||||
auto frame = decode_api.ReceiveFrame();
|
||||
|
||||
if (!frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInterlaced()) {
|
||||
auto [luma_top, luma_bottom, chroma_top, chroma_bottom] = GetInterlacedOffsets();
|
||||
auto frame_copy = frame;
|
||||
|
||||
if (!frame.get()) {
|
||||
LOG_ERROR(HW_GPU,
|
||||
"Nvdec {} failed to decode interlaced frame for top {:#X} bottom 0x{:X}", id,
|
||||
luma_top, luma_bottom);
|
||||
}
|
||||
|
||||
if (UsingDecodeOrder()) {
|
||||
host1x.frame_queue.PushDecodeOrder(id, luma_top, std::move(frame));
|
||||
host1x.frame_queue.PushDecodeOrder(id, luma_bottom, std::move(frame_copy));
|
||||
} else {
|
||||
host1x.frame_queue.PushPresentOrder(id, luma_top, std::move(frame));
|
||||
host1x.frame_queue.PushPresentOrder(id, luma_bottom, std::move(frame_copy));
|
||||
}
|
||||
FFmpeg::FrameOffsets offsets{};
|
||||
offsets.hidden = vp9_hidden_frame;
|
||||
offsets.interlaced = IsInterlaced();
|
||||
if (offsets.interlaced) {
|
||||
std::tie(offsets.luma, offsets.luma_bottom, std::ignore, std::ignore) =
|
||||
GetInterlacedOffsets();
|
||||
} else {
|
||||
auto [luma_offset, chroma_offset] = GetProgressiveOffsets();
|
||||
std::tie(offsets.luma, std::ignore) = GetProgressiveOffsets();
|
||||
}
|
||||
|
||||
if (!frame.get()) {
|
||||
LOG_ERROR(HW_GPU, "Nvdec {} failed to decode progressive frame for luma {:#X}", id,
|
||||
luma_offset);
|
||||
}
|
||||
// Send assembled bitstream to decoder.
|
||||
if (!decode_api.SendPacket(packet_data, offsets, GetFrameDimensions())) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto push = [&](u64 luma, std::shared_ptr<FFmpeg::Frame> frame) {
|
||||
if (UsingDecodeOrder()) {
|
||||
host1x.frame_queue.PushDecodeOrder(id, luma_offset, std::move(frame));
|
||||
host1x.frame_queue.PushDecodeOrder(id, luma, std::move(frame));
|
||||
} else {
|
||||
host1x.frame_queue.PushPresentOrder(id, luma_offset, std::move(frame));
|
||||
host1x.frame_queue.PushPresentOrder(id, luma, std::move(frame));
|
||||
}
|
||||
};
|
||||
|
||||
while (auto result = decode_api.ReceiveFrame()) {
|
||||
auto& [frame, frame_offsets] = *result;
|
||||
if (!frame) {
|
||||
continue;
|
||||
}
|
||||
if (frame_offsets.interlaced) {
|
||||
auto frame_copy = frame;
|
||||
push(frame_offsets.luma, std::move(frame));
|
||||
push(frame_offsets.luma_bottom, std::move(frame_copy));
|
||||
} else {
|
||||
push(frame_offsets.luma, std::move(frame));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
#include <queue>
|
||||
|
||||
|
|
@ -46,12 +47,19 @@ protected:
|
|||
virtual std::tuple<u64, u64, u64, u64> GetInterlacedOffsets() = 0;
|
||||
virtual bool IsInterlaced() = 0;
|
||||
|
||||
void SetFrameDimensions(s32 width, s32 height);
|
||||
|
||||
std::optional<FFmpeg::FrameDimensions> GetFrameDimensions() const {
|
||||
return frame_dimensions;
|
||||
}
|
||||
|
||||
FFmpeg::DecodeApi decode_api;
|
||||
Host1x::Host1x& host1x;
|
||||
const Host1x::NvdecCommon::NvdecRegisters& regs;
|
||||
s32 id;
|
||||
bool initialized : 1 = false;
|
||||
bool vp9_hidden_frame : 1 = false;
|
||||
std::optional<FFmpeg::FrameDimensions> frame_dimensions;
|
||||
};
|
||||
|
||||
} // namespace Tegra
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ bool H264::IsInterlaced() {
|
|||
|
||||
std::span<const u8> H264::ComposeFrame() {
|
||||
host1x.gmmu_manager.ReadBlock(regs.picture_info_offset.Address(), ¤t_context, sizeof(H264DecoderContext));
|
||||
const auto& params = current_context.h264_parameter_set;
|
||||
SetFrameDimensions(static_cast<s32>(params.pic_width_in_mbs) * 16,
|
||||
static_cast<s32>(params.frame_height_in_mbs) * 16);
|
||||
|
||||
const s64 frame_number = current_context.h264_parameter_set.frame_number.Value();
|
||||
if (!is_first_frame && frame_number != 0) {
|
||||
frame_scratch.resize_destructive(current_context.stream_len);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ std::tuple<u64, u64, u64, u64> VP8::GetInterlacedOffsets() {
|
|||
|
||||
std::span<const u8> VP8::ComposeFrame() {
|
||||
host1x.gmmu_manager.ReadBlock(regs.picture_info_offset.Address(), ¤t_context, sizeof(VP8PictureInfo));
|
||||
SetFrameDimensions(current_context.frame_width, current_context.frame_height);
|
||||
|
||||
const bool is_key_frame = current_context.key_frame == 1u;
|
||||
const auto bitstream_size = size_t(current_context.vld_buffer_size);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue