이론 48

컴퓨터 구조 기초 - 3

스택 프레임 함수 내 선언된 변수는 스택에 할당됨. 함수 호출 과정에서 할당되는 메모리 블록(지역변수 선언 등으로 할당되는)을 가리켜 스택 프레임이라 한다. 스택프레임은 함수에 종속된다. 함수가 종료되면 스택프레임이 반환된다. . sp 레지스터 스택을 쌓기 위해서는 현재까지 저장한 데이터의 위치를 알아야겠지? 이를 기억하기 위해 CPU내에 sp(stack pointer)레지스터가 존재함. 스택 프레임이 반환되면 sp레지스터를 움직여야 하는데, 문제는 얼마나 움직여야 하는지를 모른다. 그래서 또 이를 기억하기 위해 프레임 포인터(FP)가 존재한다. . 프레임 포인터 스택프레임이 반환되면 sp를 fp위치로 맞추면 그만임. 그럼 fp값들은 어디에 보관? 함수가 호출되면 그때 스택에 fp값을 저장함. 반환될 때..

이론/기초 2023.07.09

컴퓨터 구조 기초 - 2

레지스터 크기와 명령어 16비트 컴퓨터가 있다고 가정하자. 그러면 레지스터 사이즈도 16비트인 게 좋을 것이다. 그리고 16비트의 레지스터 r0~r7이 있다고 하자. 명령어 역시 레지스터 크기와 같아야 좋으니까 16비트라고 하자. 자 그럼 16비트로 어떻게 명령어를 구성할 것인가? 명령어의 종류가 8개인 컴퓨터라고 가정하자. 명령어가 8개이니까 이 모든 명령어를 식별하기 위해서는 3비트가 필요하다. 사칙연산 만들어보기 사칙 연산을 예로 들어 보자. A = B+C 를 의미하는 명령어를 구현하고 싶다. 어떻게 해야 할까? 우선 '덧셈'이라는 명령에 해당하는 id가 있을 것이다(3비트) 그리고 B+C의 값을 저장할 레지스터가 필요하다. 대충 레지스터도 r0~r7까지 8개가 있다고 하자. 레지스터의 주소를 구분..

이론/기초 2023.07.01

컴퓨터 구조 기초 - 1

CPU ALU, 레지스터, 컨트롤 유닛, 버스인터페이스 로 구성. ALU는 산술연산+AND/OR 논리연산을 수행 컨트롤 유닛은 CPU가 처리해야 할 명령어를 해석하고 적절한 신호를 CPU의 다른 블록에 준다. 레지스터 셋은 CPU가 연산을 하는데 필요한 데이터를 임시적으로 저장할 메모리 공간. 버스인터페이스는 하드웨어 장치끼리 데이터를 주고밭는 매개체가 I/O 버스. 이런 버스의 프로토콜을 이해하는 것이 이 인터페이스. 클럭 펄스(Clock Pulse) : CPU는 이 클럭신호에 맞춰서 일을 함. 왜? 동기화 하려고. 프로그램의 실행 과정 전처리기 -> 컴파일러 -> 어셈블러 -> 링커 -> 실행 전처리기 : #define같이 #으로 시작하는 지시자의 지시에 따라 소스코드를 변경한다. 컴파일러 : 소스코..

이론/기초 2023.06.25

N번째 난수 값 얻어오기

문제 어떤 난수생성기가 있다고 가정하자. 이 난수 생성기로부터 N번째에 있는 난수를 얻고 싶다. 어떻게 해야 할까? 아니 애초에 위와 같은 상황은 무엇일까? 당신이 랜덤한 스테이지 A,B,C,D를 만든다고 가정하자. 한 스테이지는 1000개의 난수 시퀀스를 필요로 한다. 어떤 난수 생성기가 생성한 1001~2000번째의 난수를 이용해 A스테이지를 만들었다. 그리고 2001에서 3000까지의 난수를 이용해 B스테이지를 만들었다. 이때 B스테이지에 있던 유저가 다시 A스테이지로 돌아갔다고 하자. 아니면 4001에서 5000번째까지의 난수를 필요로 하는 D스테이지로 곧바로 들어간다면? 과거에 생성했던 난수 시퀀스를 어딘가에 저장해 둔다거나 혹은 0번째부터 다시 Next()를 호출하며 목표로 하는 시퀀스까지 도..

이론/일반 2023.06.18

(기초) 포워드 VS 디퍼드 렌더링

렌더링 방식 언리얼이나 유니티같은 상용 엔진은 기본적으로 포워드(Forward) 렌더링과 디퍼드 (Deferred) 렌더링 방식을 지원한다. 이거 두개가 젤 유명한데 뭔 차이일까? 디퍼드 렌더링 (Deferred Rendering) 디퍼드 랜더링은 많은 수의 동적 라이트를 괜찮은 성능으로 처리할 수 있다. 따라서 PC 및 콘솔 게임에서 널리 쓰인다. 그러나 기기의 성능이 어느 정도 받쳐주어야 하며, 한 번에 여러 개의 버퍼에 한꺼번에 렌더링 하는 멀티 렌더 타겟 기능이 필요하다. 멀티 렌더 타겟을 이용해서 여러 개의 지오메트리 버퍼(G버퍼)에 불투명(Opaque)한 오브젝트들의 정보를 렌더링한다. 이때 버퍼에는 다양한 정보가 기록되고, 모든 오브젝트들을 버퍼에 렌더링 한 후 이 정보들을 토대로 라이팅을 ..

이론/그래픽스 2022.07.13

클로저 (Closure)

클로저? 아래 프로그램의 add3, add5는 각각 넘겨받은 숫자에 3,5를 더해서 반환하는 함수이다. using System; public static class Prgoram { public static void Main(string[] args) { var add3 = Adder(3); var add5 = Adder(5); Console.WriteLine(add3(10)); //13을 출력 Console.WriteLine(add5(10)); //15를 출력 } public static Func Adder(int add) { return (int num) => { return num + add; }; } } add3, add5를 생성할 때, Adder메서드에 각각 3과 5를 넘겨주고 add3과 add..

이론/일반 2022.06.25

예외(Exception) 써야할까?

예외처리의 동작방식 우선 예외에는 대안이 있다. 바로 에러 코드를 함수에서 리턴하는 것이다. 즉, 예외를 쓰려면 에러 코드를 리턴하는 것보다 더 좋아야 한다. 그렇다면 예외가 어떻게 동작하는지 간단히 보자. void bar() { throw std::runtime_error("some exception"); } void foo() { bar(); } int main() { try { foo(); } catch(...) { } } 처음에 main함수에 대한 스택 프레임이 올라가고, 그다음 foo 스택 프레임이 올라가고, 그다음에 bar 함수에 대한 스택 프레임이 올라간다. bar함수에서 예외가 던져지면 exception 객체가 힙에 생성되고 bar함수의 스택 프레임은 스택에서 pop이 된다. 이어서 foo..

이론/일반 2022.06.19

객체 풀

왜써야댐 객체를 생성하기 위해 힙 메모리를 할당/해제하다보면 메모리 단편화가 생긴다. 메모리 단편화는 특히 메모리가 부족한 모바일 환경에서 치명적이다. 객체 풀은 사용될 객체들을 위한 메모리를 미리 크게 잡아놓음으로써 메모리 단편화를 예방한다. 게다가 일부 관리 언어에서 GC호출 빈도를 줄여주는 효과도 있다. 그럼 언제씀 객체 풀 패턴은 다음과 같을 때 사용하면 좋다. 객체를 빈번하게 생성/삭제한다. 객체들의 크기가 비슷하다(같다). 객체를 힙에 생성하는 게 느리거나 메모리 단편화가 우려된다. DB나 네트워크 연결같이 접근 비용이 비싸면서 재사용 가능한 자원을 객체가 캡슐화하고 있다. 구현 아래와 같은 파티클 객체가 있다. class Particle { public: Particle() : frame_(..

데이터 지역성

https://tsyang.tistory.com/68 Data-oriented Design (데이터 지향 설계, DoD) CppCon 2014 - Mike Acton의 "Data-Oriented Design and C++"을 주로 참고해서 씀. https://www.youtube.com/watch?v=rX0ItVEVjHc 인트로 1. 소프트웨어는 플랫폼이다. 2. 코드는 실제 세계의 모델을 중심으로 설.. tsyang.tistory.com 데이터 지역성을 활용해야 하는 이유와 아이디어는 위 글에 써있다. 이 글에서는 구현에 대해 다룬다. 데이터 지역성 패턴 데이터 지역성 패턴은 성능 문제가 있을 때 써야한다. 필요 없는 곳에 적용해봐야 코드만 복잡해지고 유연성만 떨어진다. 특히 데이터 지역성 패턴은 성능..

업데이트 메서드

2022.01.31 - [이론/디자인패턴] - 게임 루프 게임 루프 게임 루프 게임 루프는 게임 시간 진행을 유저 입력, 프로세서 속도(!)와 디커플링 한다. 유저 입력은 알겠는데 프로세서 속도와 디커플링 한다는게 무슨 말일까? 굉장히 간단한 게임 루프를 보 tsyang.tistory.com 업데이트는 어떻게 게임 루프에 루프는 간략하게 다음과 같다. while(true) { processInput(); update(); render(); } update() 안에서는 게임의 개체들을 시뮬레이션한다. 그런데 어떻게? update() 안에 직접 각각의 개체들을 움직이는 코드를 작성해야 할까? 만약에 개체의 종류가 수백 가지라면? 코드가 점점 유지 보수하기 어려워질 것이다. 당연히 이런 경우 해결책은 간단하다..