tak jak w tytle, jak w assemblerze narysować punkt o współrzędnych X,Y i koloru RED,GREEN,BLUE, i że by działało w konsoli
void Point(x,y,r,g,b)
{
__asm
{
}
}
tak jak w tytle, jak w assemblerze narysować punkt o współrzędnych X,Y i koloru RED,GREEN,BLUE, i że by działało w konsoli
void Point(x,y,r,g,b)
{
__asm
{
}
}
Najlatwiej chyba w mode 13h cos takiego: https://devdocs.inightmare.org/tutorials/x86-assembly-graphics-part-i-mode-13h.html
Chyba nie masz pojęcia o czym piszesz, technicznie na konsoli nie rysujesz pixelami, tylko podajesz pozycje wiersza kolumny znak oraz kolor, ponadto w zależności od platformy robi sie to inaczej.
BitBlt można malować w konsoli
No czyli nie masz pojęcia o czym piszesz, BitBlt jest z winapi i nie rysuje w konsoli tylko używa sterownika graficznego interfejsu. Poczytaj może jak od środka działa ta biblioteka i będziesz wiedział czy jesteś w ogóle w stanie to napisać w czystym ASM.
proszę BitBlt na konsoli DrawConsole.rar lkawisze A,W,S,D,Esc-exit a tak w ogóle BitBlt jest z GDI ....
wracając do tematu,,, jak narysować pixel w assemblerze w konsoli przy 24 bitowej grafice?
@wilkwielki: zaimplementowanie problemu w ASM samo w sobie nie rozwiązuje problemów.
Najpierw zrób wersję bez ASM, napisz benchmarki, odszukaj wąskie gardła , optymalizuj, zrób parę iteracji
I może wtedy zastanów się czy warto ASM
Kolejna sprawa że rysowanie UI bez wsparcia sprzętowego to już na starcie porażka
Przeglądam twoje starsze posty i nie rozumiem, dlaczego porzuciłeś pomysł korzystania z OpenGL (albo DirectX, Vulcan, nie wiem czego się teraz najczęściej używa) na rzecz jakiegoś dziwnego podejścia z użyciem "assemblera w konsoli"?
Jeśli robisz to dla zabawy, to jeszcze spoko. Trochę jak ludzie, którzy implementują Dooma w Excelu albo za pomocą drukarki odtwarzają muzykę z Mario. Jeśli jednak to część większego praktycznego celu, to te wątki to jak problem XY https://xyproblem.info/
Być może to, co robisz, po prostu przerosło konsolę i może czas to przepisać na program okienkowy?
Albo jeśli robisz faktycznie narzędzie linii poleceń, które powinno być obsługiwane z konsoli, to zamiast wyświetlać animację w oknie, mógłbyś generować (zapewne za pomocą jakiejś biblioteki) poszczególne klatki filmiku i zapisać do pliku jako video (albo nawet takie narzędzie mogłoby działać jak serwer i streamowałby animację, którą mógłbyś sobie zobaczyć przez przeglądarkę).
Zamiast skupiać się na wyświetlaniu grafiki, może lepiej pomyśleć w ten sposób, że program komputerowy bierze jakieś dane, transformuje je i wypluwa inne dane na wyjściu (to wyjście nie musi być wcale ekranem monitora). No ale nie wiem, co dokładnie robisz. Być może lepiej zrezygnować w ogóle z idei pisania programu konsolowego.
No i jak masz problemy z wydajnością, to może twój algorytm jest po prostu do d**y? I należałoby pomyśleć nad tym najpierw. Może gdzieś robisz jakieś dziwne zagnieżdżone pętle czy inne rzeczy, że ci fpsy spadają.
Zaskoczę cię, ale w assemblerze się programuje tak samo jak w C czy C++, to też język programowania.
BitBlt, to wywołanie systemowe, czyli możesz przeiterować TEB thread environment block, czy wywołać z biblioteki wingdi z poziomu assemblera.
Same stworzenie karty graficzne jest dosyć proste, potrzebujesz FPGA układu, tam tworzysz buffer, który wysyłasz na jakiś protokół tam vga, hdmi.
VGA jest mega proste, kodujesz sobie 255 red jako 3,3V, a 0 RED jako 0V dla pixela i sobie przeskakujesz czasowo vertykalnie i horyzontalnie, żeby na monitorze wyświetlić pixele.
A na komputerze tworzysz też buffer, wycinek ramu, o wielkości tego ekranu, używasz DMA, direct memory access, żeby automatycznie przesyłał ci z tego ramu do twojej karty na fpga przez usb obraz do tego buffora gdzie transportujesz na monitor obraz.
I teraz w Assemblerze czy C++ czy innym języku po prostu wpisujesz w ten rejon pamięci dane, np. kolor pixela na gridzie siatce i to się pojawia na ekranie.
Teraz że to system wysokopoziomowy to od tak nie możesz sobie grzebać po pamięci więc, sobie robisz jakiś plik/urządzenie, do którego jak będziesz pisać to będzie aktualizować dany obszar pamięci, który DMA przesyła, potem w programie mapujesz sobie te urządzenie i korzystasz jakby to był kawałek pamięci ram.
Tak też jest jak masz Baremetal cpu, masz podmapowane w ramie framebuffer do którego możesz pisać.
Na windowsie musisz z winapi korzystać, gdyż nie masz pełnej władzy nad systemem, a jedynie za pomocą interfaceu.
BitBlt ma swoją implementację można przy debugowaniu kernela przejrzeć lub jest jedna wersja windowsa, która wyciekła do netu i na niej można się doszkolić czytając kod źródłowy jak pewne operacje system przeprowadza.
A tak jak masz tablicę w C
int tab[100];
i chcesz tam zapisać kolor RGBA
tab[50] = 0xFF000000
to w assemblerze też tak zapisujesz
lea rax, $tab+50
mov [rax], 0xff000000
To jest to samo zwykły język programowania, specjalne instrukcje tylko są dodatkowe jak i/o ports, mapowanie i/o w ramie to się nie różni.
Korzystanie np. z tych starodowanych BIOS instrukcji do podczas uruchomienia komputera, do ramu jest kopiowany z eeprom/flash vektor instrukcji przerwań z ich implementacją i potem za pomocą przerwań można sobie korzystać z tych małych gotowych programów.
@wilkwielki
Podstawowe pytanie - czy używasz Windowsa 95 lub 98 lub ME czy nowszej wersji?
Poniżej opisuję główne różnice między starym systemem Windows 98 a nowszymi systemami z rodziny Windows 7/Windows 8/Windows 10/Windows 11 w kontekście relacji z systemem DOS, trybów graficznych (VGA, SVGA), dostępu do pamięci wideo i rysowania „bezpośredniego”. Zaraz też opiszę, czy w nowszych wersjach można „przełączyć się do trybu VGA/SVGA” i rysować bezpośrednio, oraz co było możliwe w trybach DOS/SVGA w starych czasach.
Windows 98 i DOS — pełna zgodność w dużym stopniu
Windows 7/8/10/11 – rodzina NT i ograniczony dostęp do sprzętu
Czy w nowszych Windows można przełączyć się do trybu VGA/SVGA i rysować w pamięci bezpośrednio?
Odpowiedź: nie w tym samym sensie, lub tylko w bardzo ograniczonym zakresie. Oto szczegóły:
W Windows 98:
W Windows 7/8/10/11:
Dlatego — jeśli chcesz robić takie „bezpośrednie rysowanie w pamięci wideo” jak w czasach DOS-owych, w Windows 7/8/10/11 będzie to znacznie trudniejsze lub wręcz niemożliwe bez użycia specjalnych warstw (np. sterownika w trybie kernela) albo uruchomienia DOS-u/lub maszyny wirtualnej.
Podsumowanie kluczowych wniosków
Teraz odpowiedz mi na pytanie której wersji Windowsa używasz? Jeśli Windowsa 95/98/ME to musisz przełączyć się do trybu SVGA jeśli Twoja karta graficzna obsługuje SVGA i wtedy możesz narysować piksel. Jeśli używasz Windowsa 7/8/10/11 to po prostu wywołaj funkcję SetPixel w swoim kodzie asemblerowym:
#include <windows.h>
void __stdcall Point(int x, int y, int r, int g, int b)
{
HDC hdc = GetDC(GetConsoleWindow());
if (!hdc) return;
COLORREF col = RGB(r, g, b);
__asm {
push col ; 4th param = COLORREF color
push y ; 3rd param = int y
push x ; 2nd param = int x
push hdc ; 1st param = HDC hdc
call SetPixel ; wywołanie WinAPI SetPixel
; wynik w eax (COLORREF lub –1)
}
ReleaseDC(GetConsoleWindow(), hdc);
}
@wilkwielki napisał(a):
tak ale architektura musi być win32 bo pod x64 nie działa
Istnieje konkretne techniczne uzasadnienie dlaczego w kompilatorze Microsoft Visual C++ (dla platformy x64) nie można używać wstawek asemblerowych (__asm { … }) tak jak w platformie x86. Poniżej wyjaśniam dlaczego, co to oznacza w praktyce i jak programować w asemblerze dla architektury x64.
Dlaczego __asm { … } nie działa w x64 w MSVC
Kilka ważnych powodów:
Oficjalna dokumentacja Microsoftu mówi:
„Inline assembler is not supported on the ARM and x64 processors. …” https://learn.microsoft.com/en-us/cpp/assembler/inline/inline-assembler?view=msvc-170
„One of the constraints for the x64 compiler is no inline assembler support. This means that functions that can’t be written in C or C++ will either have to be written as subroutines or as intrinsic functions supported by the compiler.” https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170
Czyli formalnie Microsoft zdecydował, że dla architektury x64 (64-bitowej) nie będzie wspierał wstawek asemblerowych w kodzie C/C++ za pomocą__asm.
Powody techniczne i optymalizacyjne:
Alternatywy przewidziane przez Microsoft:
.asm (np. za pomocą Microsoft Macro Assembler MASM lub ML64), i linkowanie go z kodem C/C++. W ten sposób asembler jest „oddzielony” od kompilatora C/C++ i nie miesza się inline w kodzie wysokiego poziomu. https://forums.codeguru.com/showthread.php?565195-__asm-equivalent-for-64-bit-programmingJak programować w asemblerze w architekturze x64
Skoro inline wstawki nie są obsługiwane w MSVC dla x64, oto sposoby, jakie można zastosować:
a) Metoda: Plik .asm (zewnętrzny moduł assemblerowy)
Tworzysz plik np. mysub64.asm zawierający kod asemblerowy w składni MASM/ML64 (lub innej wspieranej).
Komponujesz go razem z projektem w Visual Studio lub innym środowisku jako element build: kod assemblerowy → .obj, następnie linkujesz z projektem C/C++.
W pliku C/C++ deklarujesz funkcję „extern” i wywołujesz ją jak zwykłą funkcję. Musisz stosować konwencję wywołania x64 (w Windows: pierwszy argument w RCX, drugi w RDX, trzeci w R8, czwarty w R9; reszta na stosie) — który jest opisany w dokumentacji. https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions?view=msvc-170
Przykład (bardzo uproszczony):
; mysub64.asm
PUBLIC MyAsmFunc
.code
MyAsmFunc PROC
; kod w x64
ret
MyAsmFunc ENDP
END
W C++:
extern "C" void MyAsmFunc();
// … w kodzie:
MyAsmFunc();
b) Metoda: Użycie intrinsics lub funkcji wbudowanych
__int64 _addcarry_u64(...), lub instrukcji SSE/AVX), lepiej użyć intrinsics dostarczonych przez kompilator niż pisać pseudosurowy kod asemblerowy. Dokumentacja Microsoftu wskazuje, że w x64 inline asm nie ma — zamiast tego intrinsics. https://learn.microsoft.com/en-us/cpp/assembler/inline/writing-functions-with-inline-assembly?view=msvc-170#include <intrin.h>
unsigned __int64 result = _addcarry_u64(carryIn, a, b, &carryOut);
c) Kompilator alternatywny
.asm, możesz użyć innego kompilatora niż MSVC — np. GCC/Clang na Windows (MinGW-w64), które wspierają inline assembly nawet dla architektury x64. Dokumentacja mówi, że MSVC to ogranicza. https://en.cppreference.com/w/c/language/asm.htmld) Uwagi specjalne — konwencje wywołania, prolog/epilog
Podsumowanie
__asm { … }) w kodzie dla architektury x64. To nie kaprys — ma to uzasadnienie techniczne (kompilator, optymalizacje, konwencje wywołania, bezpieczeństwo kodu)..asm i linkować ją z projektem, lub
dziękuje panu Igor1981 za tak wielką wypowiedź
jak coś to w msys2 clang64 działa:
#include <iostream> // Dołączenie biblioteki standardowej do operacji wejścia/wyjścia
// Funkcja dodająca 1 do wartości x używając inline assemblera
int add_one(int x) {
int result; // Zmienna lokalna do przechowania wyniku operacji
// Inline assembler w składni AT&T:
asm volatile(
"movl %1, %%eax;" // Przenieś wartość x do rejestru EAX
"incl %%eax;" // Zwiększ wartość w rejestrze EAX o 1
"movl %%eax, %0;" // Przenieś wynik z rejestru EAX do zmiennej result
: "=r"(result) // Lista wyjściowa: result jako output w dowolnym rejestrze
: "r"(x) // Lista wejściowa: x jako input w dowolnym rejestrze
: "%eax" // Lista rejestrów modyfikowanych: EAX zostaje zmieniony
);
return result; // Zwróć wynik operacji
}
// Główna funkcja programu - punkt wejścia
int main() {
int value = 41; // Zainicjalizuj zmienną value wartością 41
// Wyświetl wynik na standardowym wyjściu używając funkcji add_one
std::cout << "Result = " << add_one(value) << std::endl;
return 0; // Zwróć 0 oznaczając pomyślne zakończenie programu
}
wszystko fajne tylko szkoda bo już nie używam g++
@wilkwielki zrozum jedną ważną rzecz. DOS i Windows bardzo różnią się od siebie. Windows 95/98/ME i Windows NT/2000/XP/Vista/7/8/10/11 też bardzo różnią się od siebie. Podstawową różnicą między DOSem, a Windowsem jest to, że aplikacje użytkownika w DOSie mają bezpośredni pełny dostęp do sprzętu, a aplikacje użytkownika w Windows mają zablokowany przez system bezpośredni dostęp do sprzętu i mogą komunikować się ze sprzętem tylko i wyłącznie za pośrednictwem systemu operacyjnego. W DOSie mogłeś komunikować się ze sprzętem za pomocą przerwań, za pomocą portów, miałeś dostęp do bufora pamięci karty graficznej pod adresem A000h. W Windowsie tego wszystkiego nie ma. W Windowsie masz podział na aplikacje działające w trybie jądra i aplikacje działające w trybie użytkownika. Tylko aplikacje działające w trybie jądra mają dostęp do sprzętu i tymi aplikacjami są sterowniki. One za pomocą portów komunikują się ze sprzętem. Taka zwykła aplikacja którą piszesz będzie działała w trybie użytkownika i ona nie ma bezpośredniego dostępu do sprzętu. W Windowsie komunikacja ze sprzętem wygląda w ten sposób, że aplikacja użytkownika wywołuje odpowiednią funkcję Win Api. Funkcja Win Api komunikuje się z odpowiednim sterownikiem urządzenia. I ten sterownik komunikuje się z urządzeniem i przekazuje mu co ma wykonać. Inaczej się nie da. System został zaprojektowany w taki sposób żeby inaczej się nie dało. Takie rozwiązanie znacznie zwiększa stabilność systemów Windows i sprawia, że blue screen nie wyświetla się tak często jak w Windows 95/98/ME (o tych systemach opowiem za chwilę). W Windowsie nie masz przerwań. Przerwania są w DOSie. Można powiedzieć, że Win Api jest pod Windowsem odpowiednikiem tego czym były przerwania w DOSie. Jeżeli chcesz pod Windowsem programować bardzo nisko poziomowo, najniżej jak się da, to musisz korzystać z funkcji Win Api. Niżej poziomowo już się nie da. To jest najniższy dostępny poziom pod Windowsem.
O ile w DOSie używanie asemblera potrafiło zwiększyć wydajność bo miałeś bezpośredni dostęp do sprzętu i mogłeś na przykład skomunikować się z urządzeniem za pomocą portów co było najszybsze, to w Windowsie nie ma to sensu bo i tak zawsze musisz wywołać funkcję Win Api, która skontaktuje się ze sterownikiem urządzenia i to sterownik będzie bezpośrednio komunikował się ze sprzętem. To czy wywołasz funkcję Win Api w asemblerze czy w C czy w C++ czy w jakimkolwiek innym języku programowania, który na to pozwala, to pod kątem wydajności nie ma żadnego znaczenia bo cała komunikacja i tak jest w kodzie funkcji Win Api i w kodzie sterownika urządzenia.
Jak chcesz zwiększyć wydajność urządzenia, na przykład karty graficznej, to musisz napisać nowy sterownik do niej, a to wymaga bardzo dużej wiedzy o tej karcie i o Windowsie. I raczej nie napiszesz lepszego sterownika niż producent karty.
I teraz jaka jest różnica między Windows 95/98/ME, a Windows NT/2000/XP/Vista/7/8/10/11? Windows 95/98/ME opierały się na DOSie i były wstecznie zgodne z DOSem. Windowsy z serii NT czyli Twój Windows 10 nie jest wstecznie zgodny z DOSem. Windows 95/98/ME pozwalały przełączyć się w tryb DOSa. Jak chciałeś odpalić Windowsa 98, to najpierw odpalał się DOS i DOS uruchamiał interfejs graficzny użytkownika, którym był Windows 98. Pod Windows 95/98/ME miałeś pełen dostęp do trybu DOSa i wszystkich jego funkcji. Miałeś dostęp do przerwań, do portów, do pamięci karty graficznej. Wystarczyło przejść do konsoli. Było też mnóstwo dziur, które pozwalały aplikacjom działającym w trybie użytkownika przejść do trybu jądra.
Tego wszystkiego nie ma już w linii NT czyli pod Windowsem NT/2000/XP/Vista/7/8/10/11. Jak odpalisz konsolę w Windows 10 to ona nie ma dostępu do DOSa bo tam nie ma żadnego DOSa. Oczywiście pod Windows XP można było odpalić aplikacje DOS, ale tylko dlatego, że Windows XP miał emulator DOSa. Emulator udawał DOSa i obsługiwał przerwania DOSa. Ale podejrzewam, że jak aplikacja napisana dla DOSa wywoływała jakieś przerwanie w DOSie, to emulator na samym końcu i tak wywoływał odpowiednią funkcję Win Api albo korzystał z jakiegoś innego mechanizmu stworzonego przez programistów Microsoftu do emulacji DOSa.
Jak odpalasz konsolę w Windows 10 to nie ma tam żadnego DOSa i nie ma tam żadnych funkcji DOS. Windows 10 nie jest zgodny wstecz z DOSem.
Najbardziej niskopoziomowy dostęp do sprzętu pod Windowsem 10 to są funkcje Win Api. Do grafiki jest GDI i Direct3D. A to czy wywołasz funkcję Win Api w asemblerze czy w C czy w C++ nie zmienia w żaden sposób wydajności i szybkości działania programu, więc po co się męczysz w asemblerze? Jeżeli chcesz nauczyć się programowania sprzętu, to Windows 10 nie jest dobrym wyborem bo dostęp do sprzętu jest mocno obudowany przez system i nie uzyskasz bezpośredniego dostępu.
Jeżeli chcesz narysować coś innego niż sam piksel, np. linię albo jakąś figurę, to wywoływanie kilka razy w pętli funkcji SetPixel nie będzie zbyt wydajne. Lepiej użyć innej funkcji z Win Api specjalnie przeznaczonej do takich celów.
wilkwielki napisał(a):
wszystko fajne tylko szkoda bo już nie używam g++
clang to nie g++
@Marius.Maximus napisał(a)]:
@wilkwielki ma swój własny wewnętrzny świat c++ który sam sobie zbudował
Ale dlaczego go atakujesz? Masz jakiś problem psychiczny? Próbujesz dowartościować się w ten sposób?
Człowiek przyszedł tu na forum żeby czegoś się nauczyć, czegoś nowego się dowiedzieć. Nie musi rozwiązywać problemów w taki sposób w jaki byś tego chciał. To jego sprawa jakie rozwiązanie wybierze. Czasami trzeba trochę pobłądzić żeby znaleźć właściwą drogę.
Ataki personalne na innych użytkowników są nie na miejscu.