Commit Graph

184 Commits

Author SHA1 Message Date
Adrià 394b6d049c
Merge pull request #2253 from Raghav314/perf/agc-draw-inputs-in-place
perf(agc): read draw vertex and index buffers in place from host imports
2026-10-10 08:19:00 +02:00
Adrià e53e26a209
Merge pull request #2378 from krishnaraya4/fix/agc-vertex-10-10-10-2-int-class
fix(shader): give 10_10_10_2 integer vertex inputs an integer type
2026-10-10 08:16:57 +02:00
Adrià 3064754c6a
Merge pull request #1547 from russhil/feat/shader-barycentric-emulation
feat(shader): emulate fragment barycentrics with a generated geometry stage
2026-10-10 08:15:00 +02:00
Adrià feea78cdd2
Merge pull request #2198 from XairRrR/fix/rect-list-fault-binding
fix(recompiler): bind the rect-list fault buffer in the tessellation control group
2026-10-10 08:14:27 +02:00
Adrià 9b67cbbd0a
Merge pull request #2022 from NahuelGenchi/fix/agc-unwritten-pixel-program
fix(agc): read an unwritten pixel program address as unset
2026-10-10 08:08:04 +02:00
Adrià 6f51afaa7e
Merge pull request #1736 from TheAggie/feat/agc-color-8888-uint
feat(agc): accept 8_8_8_8 UINT color targets
2026-10-10 07:59:59 +02:00
Adrià 29b4429870
Merge pull request #1485 from Celegans12/feat/agc-10-11-11-unorm-color-targets
feat(agc): implement 10_11_11 unorm color targets through 32-bit uint attachments
2026-10-10 07:58:55 +02:00
Dean Galvin 9c3a35b867 fix(agc): apply CMASK fast clears per tile
A CMASK that was neither all fast-cleared nor all expanded threw, so a
title that fast clears a target and then draws over part of it before the
eliminate could not run past it.

The CMASK is now decoded tile by tile: one nibble per 8x8 tile in
1024x512 metablocks of 4 KiB, addressed with the pipe-aligned
SW_64KB_Z_X CMASK equation for 16 pipes (addrlib
GFX10_CMASK_SW_PATTERN, Gfx10Lib::HwlComputeCmaskAddrFromCoord). Code 0
stores CB_COLOR_CLEAR_WORD into the tile's texels, 0xF keeps them; any
other code, a cleared tile of a DCC target and any other CMASK swizzle
mode throw. Edge tiles are included and the CMASK is then stored as
expanded.

For a resident target whose CMASK is host-imported the clear is a
compute pass recorded in stream order: it reads the nibbles from the
import, stores the clear into the cleared tiles through a UINT view of
the image and fills the CMASK expanded, so nothing waits for pending GPU
writes of the CMASK. Invalid codes it reads set a bit that the next
materialization throws on. Otherwise the CPU reads the CMASK and stores
the cleared tiles into guest memory, or fills the resident image when
every tile is cleared. A CMASK nothing has stored over since it was
expanded is skipped.

The decode requires CB_COLOR_ATTRIB3 FMASK_SW_MODE SW_64KB_Z_X with
CMASK_PIPE_ALIGNED, a 4 KiB aligned writable CMASK and texels of at most
64 bits, and CMASK_BASE_EXT is part of the draw key.

Tests: CMASK sizes and nibble addresses against addrlib; decode
rejections and draw key coverage; CPU eliminate of full, partial,
out-of-range-nibble and DCC decompress cases and invalid codes. The new
agc_driver_cmask_fast_clear GPU test draws over fast-cleared and partly
fast-cleared linear and SW_64KB_R_X targets, eliminates partial, edge
and checkerboard CMASKs through the compute pass and checks that an
invalid code it reads throws.
2026-10-10 18:20:06 +13:00
raghav314 c903d1adf9 perf(agc): read draw vertex and index buffers in place from host imports
Every draw copied its index range and its vertex ranges out of guest
memory into new host buffers (CopyDrawInput) before the GPU could read
them. A range that lies in a host import is now bound from the import
itself, at its offset in it, the way the console's input assembler reads
guest memory directly.

A range is bound in place only when the batch has no write over it that
could still land (a recorded or in-flight GPU write after the pending
results are flushed, a completion label, a queued label store, a copied
buffer a dispatch or draw writes back) and its offset in the import is a
multiple of what the reader needs: the index size, or the strictest
format alignment of the vertex attributes that share the range
(VertexCopyPlan::alignments; a copy starts its range at offset 0, so
only an in-place range can be misaligned). Otherwise it is copied as
before. The read is noted on the batch (Recorder::ReadKind::DrawInput),
so a CPU store into the range waits for the draw like the other in-place
readers, and the barrier validation sees it. Imports gain vertex and
index buffer usage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 10:22:58 +05:30
Dean 5e5c72ee33
Merge pull request #2197 from XairRrR/fix/agc-collapsed-viewport
fix(agc-driver): rasterize nothing through a zero-scale viewport
2026-10-10 17:45:01 +13:00
Dean 6377727dd9
Merge pull request #2179 from oneandonlydean/up639/depth-bounds-absent-planes
fix(agc): pass the depth bounds test when both depth planes are absent
2026-10-10 17:44:53 +13:00
Dean ea8f654350
Merge pull request #2178 from oneandonlydean/up639/resummarize-blits
fix(agc): draw nothing for resummarize draws without depth or color work
2026-10-10 17:44:46 +13:00
Dean 7538f22fde
Merge pull request #2128 from MathiasDevelopes/fix/agc-spi-ps-input-cntl-clear-state
fix(libSceAgcDriver): SPI_PS_INPUT_CNTL registers start at their clear-state value
2026-10-10 17:44:08 +13:00
Dean d3c507052a
Merge pull request #2095 from Raghav314/fix/agc-1d-color-targets
fix(agc): render into 1D color targets as one-row 2D targets
2026-10-10 17:44:00 +13:00
Dean 606d4c3d0f
Merge pull request #2063 from MarcZX100/codex/fix-agc-user-data-tail-padding
fix(agc): read shader user data without tail padding
2026-10-10 17:43:28 +13:00
Dean ead855f0cc
Merge pull request #1968 from lubaxe/fix/agc-skip-primitive-restart-index
fix(agc): leave the primitive restart index out of an indexed draw's vertex range
2026-10-10 17:43:21 +13:00
Dean 8002d11f67
Merge pull request #1915 from TheAggie/fix/agc-radv-raster-defaults
fix(agc): accept RADV's disabled conservative rasterization and out-of-order watermark
2026-10-10 17:42:34 +13:00
Dean eb283f5c8f
Merge pull request #1914 from TheAggie/feat/agc-force-dst-alpha-one
feat(agc): blend against an opaque destination for CB_COLOR_ATTRIB FORCE_DST_ALPHA_1
2026-10-10 17:42:27 +13:00
Dean 5b6c778a95
Merge pull request #1769 from TideOPL/pr/stride0-raw-range
fix(agc): apply the raw OOB_SELECT range rules to zero-stride vertex buffers
2026-10-10 17:41:11 +13:00
russhil 4a2e60546c feat(shader): emulate fragment barycentrics with a generated geometry stage
Without VK_KHR_fragment_shader_barycentric the recompiler dropped
v_interp_p1_f32 and made v_interp_p2_f32 read the attribute Vulkan
interpolated, but never wrote the I/J VGPRs: a pixel shader that read
them for anything else got 0, and v_interp_mov_f32 of P10/P20 (or P0 of
an interpolated input) needed PerVertexKHR and failed pipeline
validation.

The fallback translation now loads the I/J VGPRs and marks v_interp_p1
and v_interp_p2 with witnesses. After the front-end simplification
(SSA, folding, DCE, read-lane and masked-select elimination),
HostInterpolationChecker requires every p2 to read its J, and its p1's
I, from a barycentric of the parameter's kind, every p1 result to reach
only the matching p2 (through a write masked by the p2's EXEC, whose
inactive lanes keep the old register), no parameter read as raw
vertices and no slot shared by different interpolations. It then
lowers the witnesses to the host-interpolated attribute as before,
reruns DCE and masked-select elimination, and accepts the program only
when no barycentric read remains, so reusing the I/J VGPRs after
interpolating keeps host interpolation and the previous SPIR-V. Any other
program is translated with the barycentric path and marked as emulated:
its barycentrics become vec3 inputs (NoPerspective for the linear
weights) and its per-vertex parameters flat vec4[3] inputs, placed in
the free locations by LayoutBarycentricEmulation. The driver then
inserts a generated geometry stage between the vertex and fragment
shaders that copies the position and parameters, writes the one-hot
weights of each vertex and the three vertices' parameter values, so the
rasterizer interpolates the same weights the extension provides.

The stage needs geometryShader and a vertex shader before it;
tessellation, mesh and rect-list pipelines, other primitive types and
interfaces beyond 32 locations or the device's geometry limits throw.
CompiledShaderArtifact carries the emulation (shader disk cache format 21).

Hardware snaps window corners to 1/256 pixel before interpolating
(measured by yahya308 on an RTX 4070 Laptop and a Radeon 780M in #1547);
lavapipe snaps only for coverage (lp_rast.h FIXED_ORDER 8), so the test
accepts either reference per pixel at the original 1e-4 margin.

Sources:
- v_interp_p1_f32/v_interp_p2_f32/v_interp_mov_f32 semantics (P0,
  P10, P20, I/J): AMD RDNA2 ISA, "Parameter Interpolation".
- BaryCoordKHR/BaryCoordNoPerspKHR weights and PerVertexKHR vertex order:
  SPV_KHR_fragment_shader_barycentric, VK_KHR_fragment_shader_barycentric.
- Geometry shader triangle input order and provoking vertex: Vulkan
  specification, "Primitive Topologies" and "Geometry Shading".
- Interpolation decorations decided by the fragment input: Vulkan
  specification, "Interpolation Decorations".
- lavapipe interpolation: Mesa src/gallium/drivers/llvmpipe/lp_rast.h
  (FIXED_ORDER 8), lp_setup_tri.c (subpixel_snap for coverage only),
  lp_state_setup.c (init_args, plane setup from float positions).
2026-10-10 03:24:50 +02:00
Dean Galvin 77373c0380 fix(agc): pass the depth bounds test when both depth planes are absent
Main renders depth and stencil tests without a depth target when DB_Z_INFO and DB_STENCIL_INFO both have FORMAT INVALID (48ebf3195e): with no plane, the DB has nothing to test, and every test passes. The depth bounds test (DB_DEPTH_CONTROL bit 3) reads the same absent depth plane, but such a draw still threw "depth bounds without a depth surface". A title does this when a level loads.

Depth bounds now follow the same rule when both planes are absent. With an absent depth plane beside a present stencil plane, the bounds test still throws ("depth bounds without a depth plane"), as before.
2026-10-10 14:24:26 +13:00
Sasha Papo 98b4bdf843 fix(agc): skip an indexed draw whose indices are all restart markers
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:12:16 -04:00
Sasha Papo c0a88ce392 fix(agc): leave the primitive restart index out of an indexed draw's vertex range
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 21:12:16 -04:00
Adrià a9ac7bc4c3
Merge pull request #1580 from Zheorgyan/feat/storage-buffers-update-after-bind
feat(agc): bind storage buffers update-after-bind above the per-stage limit
2026-10-10 03:12:01 +02:00
Adrià 7876b46ff3
Merge pull request #1534 from hamb3r/codex/clearmrt-stencil-clear
fix(agc): preserve ClearMRT color writes and validate stencil clears
2026-10-10 03:09:58 +02:00
Celegans12 c4b7a7453e feat(agc): implement 10_11_11 unorm color targets through 32-bit uint attachments
CB_COLOR_INFO format 6 (COLOR_10_11_11) with NUMBER_UNORM threw in
DecodeColorFormat: Vulkan has only the B10G11R11 float format. Such a
target now renders into an R32_UINT attachment in the layout of
format-30 images (unorm11 R and G in bits 0-21, unorm10 B in bits
22-31), so later image loads of the surface read the same words.

The target format is draw state, so the packing is a specialization of
the registered pixel shader: every float MRT export also computes the
packed word (EmitFormatStoreComponent) behind specialization constant
ExportPackingBase + target, and the specialized module turns a packed
target's output into a uint4 that ValidateShaders expects. The new
request field targetExportPacking is in the module key, the result memo,
the draw key and the serialized request (version 14). Blending, partial
RGB writes, UNORM16/SNORM16/UINT16 exports, DCC and ROUND_MODE throw.
2026-10-10 02:09:27 +02:00
Zheorgyan 27e6ad1ad2 feat(agc): bind storage buffers update-after-bind above the per-stage limit 2026-10-10 02:08:15 +02:00
TideOPL 46606e9c73 test(agc): cover depth surface lookups of reused memory
agc_driver_graphics registers a D32 and a D16 surface on a mock device and looks up views at their addresses. Views of the surface's own extent in R32F or R16, and T#s that read the raw depth bits, sample the depth plane; a view of another extent, a 2D array view of another extent, an R11G11B10 view, an R32 uint view without a depth layout and an R32F view of a D16 surface return null and take the ordinary texture path. On main the first of these throws in DepthSurface::Sampled.
2026-10-10 00:44:40 +01:00
MarcZX100 622984257b test(agc): pin serialized user data size 2026-10-09 22:43:42 +00:00
MarcZX100 50f1f1aa84 fix(agc): read shader user data without tail padding 2026-10-09 22:43:42 +00:00
Adrià a00165da9e
Merge pull request #1252 from MathiasDevelopes/feat/recompiler-native-f16-rte
feat(recompiler): convert f32 to f16 natively when the device rounds 16-bit floats to nearest even
2026-10-10 00:39:15 +02:00
Adrià fc063cff85
Merge pull request #1074 from alfalfa-star/feat/agc-graphics-int64-atomics
feat(agc): accept 64-bit atomics in graphics shaders when the device enables them
2026-10-10 00:14:56 +02:00
Adrià 2d537f13bb
Merge pull request #1073 from alfalfa-star/feat/agc-uint16-color-export
feat(agc): accept UINT16_ABGR color exports into unsigned integer targets
2026-10-10 00:13:23 +02:00
Dean 2af96d1863
Merge pull request #1085 from Celegans12/fix/agc-host-heap-budget
fix(agc): throw instead of aborting when a heap mirror cannot be made
2026-10-10 08:05:48 +13:00
krishnaraya dffd449489 fix(shader): give 10_10_10_2 integer vertex inputs an integer type
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 12:49:25 -04:00
Celegans12 4709920641 fix(agc): throw instead of aborting when a heap mirror cannot be made
An address-based build whose heap mirror the device refused, or one past
APS5_HEAP_MIRROR_MIB, stopped the process inside acquireMirror. PPSA26344
hit it at 478 s with 6.8 GiB of heap mirrors beside the host imports.

- a mirror that would go past the budget first sweeps the mirrors whose
  registered range is gone, before its allocation; if it still does not
  fit, the build throws "past the budget"
- the mirror is allocated once: a refusal throws with the range, the
  Vulkan result and the mirror totals, so the draw or dispatch fails like
  any other allocation; nothing is registered for the refused range
- the BDA resource tests run with a 4 MiB mirror budget and a mock memory
  limit: a mirror past the budget is made in the swept mirror's memory,
  and a refused one fails after a single allocation attempt
2026-10-09 14:58:20 +02:00
XairRrR 8b7ff670a7 fix(recompiler): bind the rect-list fault buffer in the tessellation control group
The rect-list control and evaluation shaders put their fault buffer one
past the highest vertex or fragment binding. Bindings are grouped per
stage (RuntimeAbi::BindingNumber), so that number could fall inside
another stage's group and collide with one of its bindings, and the
draw failed with a duplicate binding. The fault buffer now uses the
TessellationControl FaultBuffer binding.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at its first rect-list draw with "duplicate shader binding".
2026-10-09 13:28:48 +02:00
XairRrR 0fc522d9be fix(agc-driver): rasterize nothing through a zero-scale viewport
A viewport whose X or Y scale is zero maps every vertex onto one line,
so triangle, strip, fan and rect-list draws through it cover no pixel.
Such draws, which titles use to skip work without rebuilding a command
buffer, get a valid 1x1 Vulkan viewport and an empty scissor instead of
throwing. Points, lines and other negative or non-finite scales still
throw.

Uncharted: Legacy of Thieves Collection (PPSA05684) stopped at such a draw with "unsupported viewport transform: scale=(0, -0, 1)".
2026-10-09 13:28:48 +02:00
Celegans12 52eb4272de fix(agc): copy an imported range once a merge extends it past its import
An address-based build maps each imported registered range through its
host import. UploadPrepare merges a descriptor range or snapshot
overlapping such a range into the range's region, and the region kept
the import even when the merge took it past the import's end, as a V#
crossing into the next registered range does. Descriptor then bound the
import's buffer beyond its size, and the BDA table mapped the whole
region, the next range included, through the import's device address.

A merge that extends a region past its end now drops the import. The
region then takes the import lookup and, with no import covering it,
the copy path, as a range crossing an image mirror's end already does.
Like every copied range, it is read-only to pointer stores.
2026-10-09 12:11:06 +02:00
MathiasDevelopes e70e81dc45 fix(libSceAgcDriver): SPI_PS_INPUT_CNTL registers start at their clear-state value
A title that never writes SPI_PS_INPUT_CNTL_0 relies on its clear-state
value 0, but the register was absent from the initial context, so every
draw of a pixel shader with interpolants was rejected with "missing
register at DWORD 0x191". All 32 SPI_PS_INPUT_CNTL registers now start at
0, as in the GFX10 clear state, both initially and after CLEAR_STATE.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 11:30:38 +02:00
raghav314 7638ade79f fix(agc): render into 1D color targets as one-row 2D targets
CB_COLOR_ATTRIB3.RESOURCE_TYPE 0 is a 1D surface (AddrResourceType
ADDR_RSRC_TEX_1D in addrlib). On GFX10, addrlib allows a 1D surface the
linear and render swizzle modes (Gfx10Rsrc1dSwModeMask) and picks its
swizzle pattern the same way as for a 2D surface (GetSwizzlePatternInfo
only tells 3D apart). So a 1D color target one row high is laid out
exactly like a 2D target one row tall, and is decoded as one.

A 1D target with a standard swizzle mode is rejected as invalid; one
with more than one row is not modeled and is rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:40:08 +05:30
Dean Galvin 24876afca9 fix(agc): draw nothing for resummarize draws without depth or color work
A draw with DB_RENDER_CONTROL.RESUMMARIZE_ENABLE recomputes the HTILE summary of the bound depth surface from its depth values. HTILE is not modeled, so such a draw with depth and stencil tests off and no color writes changes no modeled state. It now passes the maintenance check and draws nothing, instead of throwing. Resummarize draws with depth, stencil or color work, and copy and decompress draws, still throw.
2026-10-09 20:36:06 +13:00
Scott Schuster af9e60b690 fix(agc): accept RADV's point and line depth bias enable on triangle draws
With depth bias enabled, RADV sets POLY_OFFSET_PARA_ENABLE in
PA_SU_SC_MODE_CNTL next to the front and back enables, whatever the
topology; vkQuake's draws carry 0x3a46. The bit applies the offset to
points and lines, so it changes nothing for triangles, and Vulkan applies
depth bias only to polygons. It is now accepted with depth bias on
triangle topologies; point and line draws with it are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:54:22 -05:00
Nahuel Genchi 5c291a5557 fix(agc): read an unwritten pixel program address as unset
PixelProgramSkipped only treated SPI_SHADER_PGM_LO/HI_PS written as 0 as
a draw without a pixel program, while the draw decoder already reads an
unwritten address as 0 and binds the null pixel program for it. A
depth/stencil-only draw whose pixel program address was never written
was instead rejected by the precheck with "depth/stencil-only draws
without a pixel shader are not implemented".

An unwritten address is now unset in PixelProgramSkipped too, so such a
draw goes through the null pixel program like one with the address
written as 0, and one that writes color is rejected as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 02:05:48 -03:00
Scott Schuster 88cc2ea477 fix(agc): accept RADV's disabled conservative rasterization state
With conservative rasterization disabled, RADV programs
PA_SC_CONSERVATIVE_RASTERIZATION_CNTL to NULL_SQUAD_AA_MASK_ENABLE alone,
where libSceAgc writes the two INNER_TO_NORMAL overrides (0x6000). A value
made of only those bits now decodes as disabled; overestimation (0x6001) keeps
its checks, and every other mode is still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:47 -05:00
Scott Schuster 6c5b181b68 fix(agc): accept PA_SC_MODE_CNTL_1's out-of-order watermark
RADV sets OUT_OF_ORDER_WATER_MARK to 7 on every GFX10 draw, also when
OUT_OF_ORDER_PRIMITIVE_ENABLE is off. The watermark only tunes out-of-order
rasterization, which stays rejected, so the field is accepted alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:47 -05:00
Scott Schuster 1e20b4ec50 feat(agc): blend against an opaque destination for CB_COLOR_ATTRIB FORCE_DST_ALPHA_1
FORCE_DST_ALPHA_1 makes blending read a target's destination alpha as 1, as
for an RGBX surface; RADV sets it for formats without alpha. The target's
blend factors are rewritten to what they become with Ad = 1: DST_ALPHA is
ONE and ONE_MINUS_DST_ALPHA is ZERO, SRC_ALPHA_SATURATE is ZERO in the color
equation, and DST_COLOR and ONE_MINUS_DST_COLOR are ONE and ZERO in the
alpha equation. Other CB_COLOR_ATTRIB bits stay rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:24:46 -05:00
TideOPL c17c5ebd4d fix(agc): apply the raw OOB_SELECT range rules to zero-stride vertex buffers
With stride 0, OOB_SELECT 2 puts a fetch out of range only when NUM_RECORDS
is 0, and OOB_SELECT 3 only when the offset is not below NUM_RECORDS (GFX10
table in Mesa ac_descriptors.c). A one-record descriptor therefore returns
its whole element: Unreal's per-draw PrimitiveId stream is such a descriptor,
and refusing it skipped the draw. A wholly out-of-range fetch reads a zero
buffer.
2026-10-08 19:46:22 +01:00
Celegans12 97b9439d4f perf(agc): size the storage and sampled texture caches to the device
The storage image and sampled texture caches each let go of their least
recently used entries past a fixed 2 GiB, and a sampled view of a
storage image counted that image a second time.

The storage image cache keeps a quarter of the largest device-local
heap, at least the 2 GiB of before (TextureCacheBudget). The sampled
cache gets what VK_EXT_memory_budget leaves on that heap after the
memory in use outside sampled textures and cached storage images, the
storage cache's budget and an eighth of the heap budget, read at most
once a second and at least 2 GiB; without the extension it keeps the
storage cache's rule. A snapshot counts its image allocation, a texture
still bound after leaving the cache counts as sampled memory, and a
change of more than 10% is logged at most every 10 s. A nonzero
APS5_TEXTURE_CACHE_MIB sets both budgets; a view of a cached storage
image counts nothing and leaves the cache when its image does.
2026-10-08 20:24:03 +02:00
alfalfa-star a2b049d455 feat(agc): accept 64-bit atomics in graphics shaders when the device enables them
The recompiler emits OpCapability Int64Atomics for 64-bit buffer atomics
in any stage, and the device enables shaderBufferInt64Atomics when it
has it, but graphics shader validation only accepted its fixed list of
capabilities, so every draw whose shaders use one was rejected with
"SPIR-V requires unsupported device capability 12". Compute dispatches
are not validated this way and already ran them.

The device records the feature (bufferInt64Atomics in the device state
and the graphics Context) and ValidateShaders accepts Int64Atomics when
it is enabled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:16:01 +02:00