OpenCourant je komunitní fork OpenRadioss, tj. open source softwaru pro simulace havárií, nárazů a vysoce nelineárních dynamických dějů metodou konečných prvků. Společnost Siemens v loňském roce dokončila akvizici společnosti Altair Engineering, jež před čtyřmi lety uvolnila open source verzi OpenRadioss svého proprietárního softwaru Radioss. Minulý týden Siemens OpenRadioss pohřbil. Integroval jej do svého softwaru Simcenter, webovou stránku OpenRadioss přesměroval na Simcenter a repozitář OpenRadioss na GitHubu odstranil.
Pořadatelé devátého ročníku komunitního setkání správců nejen českých a slovenských sítí – CSNOG 2027, které se uskuteční 20. a 21. ledna, vyhlásili Call for Abstracts. Náměty na vystoupení mohou zájemci přihlašovat do 31. října na webu akce a vybírat mohou ze tří sekcí – správa sítí, legislativa a regulace a akademické projekty. Zveřejněny byly také Call of Partners určené sponzorům a partnerům setkání, kteří by například chtěli mít na
… více »Strata je open-source inferenční engine, který umožňuje lokálně provozovat rozsáhlý čínský model Qwen3.8-Flash-Next, který by jinak nejspíše vyžadoval serverovou infrastrukturu, na běžném herním počítači s alespoň 12 GB VRAM, 32 GB RAM a dostatkem místa na SSD. Nároky na paměť a rychlost generování se liší s použitou variantou modelu Qwen. Zdrojový kód je dostupný na GitHubu, pod licencí MIT.
Americký prezident Donald Trump oznámil vznik federální Jednotky pro superinteligenci (Super Intelligence Force), která má koordinovat postup vlády, technologických firem, náboženských organizací a dalších institucí v oblasti rychle se rozvíjející umělé inteligence (Trumpem oficiálně nazývanou superinteligencí). SIF, podřízená přímo Trumpovi, má pomoci Spojeným státům udržet v oblasti SI technologický náskok nad světem a
… více »Klient je e-mailový klient pro GNOME s nativní podporou Proton Mailu, PGP a spamfiltrem řízeným AI. Napsaný je v Go s GTK4 a libadwaita. Připojuje se přímo k Proton Mailu (bez Proton Bridge), ke Gmailu, k Seznam.cz a k libovolné schránce IMAP/SMTP. Každou novou zprávu nejdřív posoudí spamfiltr a teprve potom ji ukáže a ohlásí. Rozhraní je česky a anglicky.
Hra Doom nově běží také v SQL databázi CedarDB. Představen byl SQLDoom. Vyzkoušet lze online demo. Zdrojové kódy jsou k dispozici na GitHubu.
Multiplatformní open source aplikace scrcpy (Wikipedie) pro zrcadlení připojeného zařízení se systémem Android na desktopu a umožňující ovládání tohoto zařízení z desktopu, byla vydána v nové verzi 5.0. S podporou hardwarového dekódování videa na desktopu.
Moderní linker mold, rychlejší alternativa k LLVM lld nebo wild, byl vydán v nové major verzi 3.0.0. Přepsán byl z C++ do Rustu.
Po osmi letech od vydání verze 2.0 byla vydána nová major verze 3.0 multiplatformního editoru tagů MusicBrainz Picard (Wikipedie). Přehled novinek, vylepšení a oprav v changelogu.
Mezinárodní federace hudebního průmyslu (International Federation of the Phonographic Industry) navrhla Evropské komisi zařazení populárního open-source nástroje yt-dlp na evropský seznam 'padělků a pirátství' (EU Counterfeit and Piracy Watch List) pro rok 2027 (plné znění žádosti IFPI). IFPI ve svém podání označuje tento aktivně vyvíjený a o rozličné funkce bohatší fork youtube-dl za 'závažný problém' pro hudební průmysl, v
… více »
#define RGB_TO_YCbCrJPEG_Y(Rd, Gd, Bd) \
( + ((306 * (Rd) + 601 * (Gd) + 117 * (Bd)) >> 10))
#define RGB_TO_YCbCrJPEG_Cb(Rd, Gd, Bd) \
(128 - ((173 * (Rd) + 339 * (Gd) - 512 * (Bd)) >> 10))
#define RGB_TO_YCbCrJPEG_Cr(Rd, Gd, Bd) \
(128 + ((512 * (Rd) - 429 * (Gd) - 83 * (Bd)) >> 10))
void ycbcr_bgr_to_jpeg420(save_thread_t *th, unsigned char *from)
{
unsigned int Ypix;
unsigned int op1, op2, op3, op4;
unsigned char Rd, Gd, Bd;
unsigned int ox, oy, Yy, Yx;
unsigned char *Y, *Cb, *Cr;
Y = th->yuv_buffer;
Cb = &th->yuv_buffer[th->yw * th->yh];
Cr = &th->yuv_buffer[th->yw * th->yh + th->cw * th->ch];
oy = (th->yh - 2) * th->stride;
ox = 0;
for (Yy = 0; Yy < th->yh; Yy += 2) {
for (Yx = 0; Yx < th->yw; Yx += 2) {
op1 = ox + oy;
op2 = op1 + 4;
op3 = op1 + th->stride;
op4 = op2 + th->stride;
Rd = (from[op1 + 2] + from[op2 + 2] + from[op3 + 2] + from[op4 + 2]) >> 2;
Gd = (from[op1 + 1] + from[op2 + 1] + from[op3 + 1] + from[op4 + 1]) >> 2;
Bd = (from[op1 + 0] + from[op2 + 0] + from[op3 + 0] + from[op4 + 0]) >> 2;
/* CbCr */
*Cb++ = RGB_TO_YCbCrJPEG_Cb(Rd, Gd, Bd);
*Cr++ = RGB_TO_YCbCrJPEG_Cr(Rd, Gd, Bd);
/* Y' */
Ypix = Yx + Yy * th->yw;
Y[Ypix] = RGB_TO_YCbCrJPEG_Y(from[op3 + 2],
from[op3 + 1],
from[op3 + 0]);
Y[Ypix + 1] = RGB_TO_YCbCrJPEG_Y(from[op4 + 2],
from[op4 + 1],
from[op4 + 0]);
Y[Ypix + th->yw] = RGB_TO_YCbCrJPEG_Y(from[op1 + 2],
from[op1 + 1],
from[op1 + 0]);
Y[Ypix + 1 + th->yw] = RGB_TO_YCbCrJPEG_Y(from[op2 + 2],
from[op2 + 1],
from[op2 + 0]);
ox += 4 * 2;
}
ox = 0;
oy -= 2 * th->stride;
}
}
Šoupnul jsem to do cyklu s počtem iterací 30*20 (tj. 20s video při 30 snímcích za sekundu), rozlišení 1280x1024. Konverze je hotová za 6.243s.
Zdálo se mi to dlouho, tak jsem zkoušel optimalizovat a upatlal jsem toto:
void ycbcr_bgr_to_jpeg420_mine(save_thread_t *th, unsigned char *from)
{
unsigned bytes_per_row;
unsigned extra_per_row;
unsigned char *row;
unsigned char *end_pix;
unsigned char *end_row;
unsigned char *Y, *Cb, *Cr;
unsigned char R, G, B;
Y = th->yuv_buffer + (th->yh - 2) * th->yw;
Cb = &th->yuv_buffer[th->yw * th->yh + (th->ch - 1) * th->cw];
Cr = &th->yuv_buffer[th->yw * th->yh + th->cw * th->ch + (th->ch - 1) * th->cw];
bytes_per_row = th->width * 4;
extra_per_row = th->stride - bytes_per_row;
end_row = from + th->stride * th->height;
for (; from != end_row; from += th->stride + extra_per_row)
{
end_pix = from + bytes_per_row;
for (; from != end_pix; from += 2*4)
{
B = (from[0 + 0] + from[4 + 0] + from[th->stride + 0] + from[th->stride + 4 + 0]) >> 2;
G = (from[0 + 1] + from[4 + 1] + from[th->stride + 1] + from[th->stride + 4 + 1]) >> 2;
R = (from[0 + 2] + from[4 + 2] + from[th->stride + 2] + from[th->stride + 4 + 2]) >> 2;
*Cb = RGB_TO_YCbCrJPEG_Cb(R, G, B);
*Cr = RGB_TO_YCbCrJPEG_Cr(R, G, B);
Y[0] = RGB_TO_YCbCrJPEG_Y(from[th->stride + 2], from[th->stride + 1], from[th->stride + 0]);
Y[1] = RGB_TO_YCbCrJPEG_Y(from[th->stride + 4 + 2], from[th->stride + 4 + 1], from[th->stride + 4 + 0]);
Y[th->yw + 0] = RGB_TO_YCbCrJPEG_Y(from[0 + 2], from[0 + 1], from[0 + 0]);
Y[th->yw + 1] = RGB_TO_YCbCrJPEG_Y(from[4 + 2], from[4 + 1], from[4 + 0]);
Y += 2;
++Cb;
++Cr;
}
Y -= th->yw;
Y -= th->yw;
Y -= th->yw;
Cb -= th->cw;
Cb -= th->cw;
Cr -= th->cw;
Cr -= th->cw;
}
}
Prohodil jsem směr (btw řádky vrácené z opengl jsou v rgb bufferu opačně (horní řádek dole)), čtu odshora dolů a zapisuju odspoda nahoru. No nevím jestli to zlepšilo to, nebo jestli to zlepšilo použítí pointerů na některých místech, každopádně dostal jsem se na 4.854s.
Ale protože Jardíkovi se to pořád zdálo hodně a ten obraz se zdál být tmavý, tak jsem našel jiný vzorec na převod a zkoušel jsem to spatlat ... v assembleru.
global bgr_to_jpeg420_sse ; Y = ( ( 66 * R + 129 * G + 25 * B + 128) >> 8) + 16 ; U = ( ( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128 ; V = ( ( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128 section .data align=16 vec_alpha_1_and: align 16 dd 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF, 0x00FFFFFF vec_alpha_1_or: align 16 dd 0x01000000, 0x01000000, 0x01000000, 0x01000000 vec_dd_16: align 16 dd 16, 16, 16, 16 vec_dd_128: align 16 dd 128, 128, 128, 128 vec_y_const: align 16 dw 25, 129, 66, 128, 25, 129, 66, 128 vec_u_const: align 16 dw 112, -74, -38, 128, 112, -74, -38, 128 vec_v_const: align 16 dw -18, -94, 112, 128, -18, -94, 112, 128 section .text ; this expects these xmm registers to be set: ; xmm4 to vec_alpha_1_and ; xmm5 to vec_alpha_1_or ; xmm6 to vec_y_const ; xmm7 to vec_dd_16 ; input vector in xmm0 as (argb3, argb2, argb1, argb0) ; returns result as dwords in xmm1 (y3,y2,y1,y0) ; destroys content of xmm0, xmm2 %macro bgr_to_jpeg420_sse_get_Y 0 pand xmm0, xmm4 ; set alpha of each pixel to 1 por xmm0, xmm5 movaps xmm1, xmm0 ; copy to xmm1 pxor xmm2, xmm2 ; zero xmm2 punpckhbw xmm0, xmm2 ; interleave xmm2 with first 2 pixels, xmm = (a3,r3,g3,b3,a2,r2,g2,b2) punpcklbw xmm1, xmm2 ; interleave xmm2 with second 2 pixels, xmm = (a1,r1,g1,b1,a0,r0,g0,b0) pmaddwd xmm0, xmm6 ; xmm = (128a3+66r3 = A3,129g3+25b3 = B3,128a2+66r2 = A2,129g2+25b2 = B2) pmaddwd xmm1, xmm6 ; xmm = (128a1+66r1 = A1,129g1+25b1 = B1,128a0+66r0 = A0,129g0+25b0 = B0) pshufd xmm0, xmm0, 0b11011000 ; (A3, A2, B3, B2) pshufd xmm1, xmm1, 0b11011000 ; (A1, A0, B1, B0) movaps xmm2, xmm1 ; save xmm1 punpckhqdq xmm1, xmm0 ; xmm1 = (A3, A2, A1, A0) punpcklqdq xmm2, xmm0 ; xmm2 = (B3, B2, B1, B0) paddd xmm1, xmm2 ; xmm1 = (A3+B3, A2+B2, A1+B1, A0+B0) psrld xmm1, 8 ; xmm1 /= 256 paddd xmm1, xmm7 ; xmm1 += 16 ; xmm1 = ( y3, y2, y1, y0) %endmacro ; void bgr_to_jpeg420_sse( ; unsigned char *yuv_buffer, // rdi, must be 16B aligned ; const unsigned char *bgr_buffer, // rsi, must be 16B aligned ; unsigned int width, // rdx, must be multiple of 4 ; unsigned int height // rcx, must be multiple of 2 ; ) bgr_to_jpeg420_sse: push rax push rbx push rcx push rdx push rsi push rdi push rbp mov rbx, rdx ; rbx = width, mul will overwrite rdx later mov rax, rdx mul rcx ; rax = width * height mov rdx, rbx ; move back width to rdx mov rbp, rdi add rbp, rax ; rbp = pointer to U part mov rbx, rax shr rbx, 2 ; rbp+rbx = pointer to V part shl rax, 2 ; rax = rgb buffer size (width * height * 4) mov r9, rdx ; r9 = width shl r9, 2 ; r9 = width*4 = rgb_buffer stride add rsi, rax ; make rsi point to the last but one row sub rsi, r9 ; of rgb_buffer sub rsi, r9 shr rcx, 1 ; we process 2 rows in one loop,so make height half movaps xmm4, [rel vec_alpha_1_and] movaps xmm5, [rel vec_alpha_1_or] movaps xmm6, [rel vec_y_const] movaps xmm7, [rel vec_dd_16] movaps xmm3, [rel vec_dd_128] movaps xmm10, [rel vec_u_const] movaps xmm11, [rel vec_v_const] .__outer_loop: mov r8, rdx ; r8 = width shr r8, 2 ; r8 = width / 4 (4 pixels in one loop) .__inner_loop: movaps xmm8, [rsi] ; load the 4 pixels in first row, xmm = (argb3,argb2,argb1,argb0) movaps xmm9, [rsi+r9] ; load the 4 pixels in second row, xmm = (argb3,argb2,argb1,argb0) movaps xmm0, xmm9 ; get Y value for each pixel in the vector bgr_to_jpeg420_sse_get_Y ; xmm1 = ( y3, y2, y1, y0) pextrw eax, xmm1, 0 ; store it in yuv_buffer mov BYTE [rdi], al pextrw eax, xmm1, 2 mov BYTE [rdi+1], al pextrw eax, xmm1, 4 mov BYTE [rdi+2], al pextrw eax, xmm1, 6 mov BYTE [rdi+3], al movaps xmm0, xmm8 ; get Y value for each pixel in the vector bgr_to_jpeg420_sse_get_Y ; xmm1 = ( y3, y2, y1, y0) pextrw eax, xmm1, 0 ; store it in yuv_buffer mov BYTE [rdi+rdx], al pextrw eax, xmm1, 2 mov BYTE [rdi+rdx+1], al pextrw eax, xmm1, 4 mov BYTE [rdi+rdx+2], al pextrw eax, xmm1, 6 mov BYTE [rdi+rdx+3], al ; Calc U and V here movaps xmm0, xmm8 pavgb xmm0, xmm9 pshufd xmm1, xmm0, 0b10000000 pshufd xmm0, xmm0, 0b11010000 pavgb xmm0, xmm1 pand xmm0, xmm4 ; set alpha of each pixel to 1 por xmm0, xmm5 pxor xmm2, xmm2 punpckhbw xmm0, xmm2 ; xmm0 now contains words (a1,r1,g1,b1,a0,r0,g0,b0) movaps xmm8, xmm0 ; save it to xmm8 as U calculation will overwrite xmm0 ; calc U pmaddwd xmm0, xmm10 ; xmm = (128a1-38r1 = A1,-74g1+112b1 = B1,128a0-38r0 = A0,-74g0+112b0 = B0) pshufd xmm1, xmm0, 0b10110001 paddd xmm0, xmm1 ; xmm = (A1+B1, A1+B1, A0+B0, A0+B0) psrld xmm0, 8 ; xmm /= 256 paddd xmm0, xmm3 ; xmm += 128 pextrw eax, xmm0, 0 mov BYTE [rbp], al pextrw eax, xmm0, 4 mov BYTE [rbp+1], al ; calc V movaps xmm0, xmm8 pmaddwd xmm0, xmm11 ; xmm = (128a1-38r1 = A1,-74g1+112b1 = B1,128a0-38r0 = A0,-74g0+112b0 = B0) pshufd xmm1, xmm0, 0b10110001 paddd xmm0, xmm1 ; xmm = (A1+B1, A1+B1, A0+B0, A0+B0) psrld xmm0, 8 ; xmm /= 256 paddd xmm0, xmm3 ; xmm += 128 pextrw eax, xmm0, 0 mov BYTE [rbp+rbx], al pextrw eax, xmm0, 4 mov BYTE [rbp+rbx+1], al add rbp, 2 add rsi, 16 ; rgb_buffer += 16 add rdi, 4 ; Y += 4 dec r8 ; remaining iterations for inner loop jnz .__inner_loop add rdi, rdx ; skip the row sub rsi, r9 ; make rsi point to the 2 previous rows sub rsi, r9 sub rsi, r9 dec rcx ; decrement number of remaining rows jnz .__outer_loop ; if not zero, continue .__end: pop rbp pop rdi pop rsi pop rdx pop rcx pop rbx pop rax ret
S tímto jsem se dostal na 3.509s. Kód je docela ošklivý a patlal jsem to s instrukcema, co jsem našel v různých seznamech instrukcí po netu se válících. No a proč to sem házím ... kdyby se našel nějaký expert co by to rád zoptimalizoval, nebo poradil, kde a co tam zlepšit, .. byl bych moc vděčný.
Používám tam x86-64 registry, s xmm registry jsem se prostě nevešel a když ty konstanty nebudu mít přednačtené a budu je pak z paměti načítat v cyklu, tak to zdržuje a algoritmus to zpomalí. A když už jsem se nevešel s xmm registry, tak už jsem rovnou použil i x86-64 GPR.
Tiskni
Sdílej:
Kromě šumu je analogová technika ve všech vlastnostech o mnoho řádů napřed. To co se dá v analogové technice vyřešit součástkami za 10 Kč, na vyřešení stejné operace v digitální technice je potřeba stroj za sto tisíc dolarů a ještě bude pokulhávat za analogem.Pokud si vyberete jednu z těch několika málo operací, které se dají analogově snadno realizovat, tak ano
Ale rád se nechám přesvědčit – stačí, když ukážete, jak jednoduše analogově spočítat RSA
Mým výsledkem má být yuv420, pro každé 4 pixely (2x2) je tam jeden U a jeden V. Takže když mám pro 4 pixely už 4 Y', tak abych mohl použít ten vzorec řekněme pro U, musel bych nejdříve zprůměrovat B hodnoty pro ty 4 pixely, zprůměrovat Y hodnoty pro ty pixely a použít vzorec.
Momentálně to dělám tak, pro každý pixel vypočítám Y, zprůměruju rgb hodnoty pro 2x2 sousední pixely a spočtu U. Pravděpodobně by mi použítí "jednodušší" vzorce v tomto případě moc nepomohlo. Leda bych U nepočítal z průměrů ale pouze z jednoho pixelu, ale pak bych asi nedostal hezký výsledek.
Jak jsem psal, nerozumím tomu do detailu. Ale jednu věc vím zcela určitě. Volba lepšího algoritmu a pohrání si s matematikou dává mnohem větší zrychlení, než ďábelsky kódovat nanosekundy pomocí asm. Možná se ukáže, že to není k ničemu.Jenže Jardík obvykle jde cestou předčasné optimalizace a ukazuje nám proč se nemá dělat. (viz. jeho starší blog kde ďábelsky optimalizoval v ASM, až se dostal na stejný čas jako naivní C program)
>> 2" u onoho supsamplingu se mi také moc nelíbí, protože to se může bez ztráty kytičky udělat až na konci a získámé tím trochu vyšší přenost.
No a ještě bych nejspíš držel dva ukazatele do RGB pole from, pošouplé o th->stride a jenom je inkrementoval, protože i když z toho překladač udělá nepřímé adresování, stále to bude sahat do paměti. To samé i u výsledného Y a th->yw.