Skip to content

Commit 584258f

Browse files
committed
добро пожаловать в GPU вычисления
1 parent 68ccd8c commit 584258f

10 files changed

+459
-113
lines changed

game/GPUAutomaton.cpp

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#include "GPUAutomaton.h"
2+
3+
GPUAutomaton::GPUAutomaton(int width, int height)
4+
: gridWidth(width), gridHeight(height), gridSize(width* height), bufferIndex(0) {
5+
CreateComputeShader();
6+
SetupBuffers();
7+
}
8+
9+
GPUAutomaton::~GPUAutomaton() {
10+
glDeleteProgram(computeProgram);
11+
glDeleteBuffers(2, cellsBuffer);
12+
}
13+
14+
void GPUAutomaton::CreateComputeShader() {
15+
const char* computeShaderSource = R"(
16+
#version 430 core
17+
18+
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
19+
20+
layout(std430, binding = 0) buffer CurrentCells {
21+
int current[];
22+
};
23+
24+
layout(std430, binding = 1) buffer NextCells {
25+
int next[];
26+
};
27+
28+
uniform ivec2 gridSize;
29+
30+
int countLiveNeighbors(ivec2 pos) {
31+
int count = 0;
32+
for(int dy = -1; dy <= 1; ++dy) {
33+
for(int dx = -1; dx <= 1; ++dx) {
34+
if(dx == 0 && dy == 0) continue;
35+
ivec2 neighbor = (pos + ivec2(dx, dy) + gridSize) % gridSize;
36+
count += current[neighbor.y * gridSize.x + neighbor.x] > 0 ? 1 : 0;
37+
}
38+
}
39+
return count;
40+
}
41+
42+
void main() {
43+
ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
44+
if (pos.x >= gridSize.x || pos.y >= gridSize.y) return;
45+
46+
int currentState = current[pos.y * gridSize.x + pos.x];
47+
int neighbors = countLiveNeighbors(pos);
48+
int nextState = 0;
49+
if (currentState == 1) { // Æèâàÿ êëåòêà
50+
if (neighbors == 2 || neighbors == 3) nextState = 1;
51+
} else { // Ìåðòâàÿ êëåòêà
52+
if (neighbors == 3) nextState = 1;
53+
}
54+
next[pos.y * gridSize.x + pos.x] = nextState;
55+
}
56+
)";
57+
58+
GLuint computeShader = glCreateShader(GL_COMPUTE_SHADER);
59+
glShaderSource(computeShader, 1, &computeShaderSource, NULL);
60+
glCompileShader(computeShader);
61+
CheckShaderCompilation(computeShader, "Compute Shader");
62+
63+
computeProgram = glCreateProgram();
64+
glAttachShader(computeProgram, computeShader);
65+
glLinkProgram(computeProgram);
66+
CheckProgramLinking(computeProgram);
67+
glDeleteShader(computeShader);
68+
}
69+
70+
void GPUAutomaton::SetupBuffers() {
71+
glGenBuffers(2, cellsBuffer);
72+
for (int i = 0; i < 2; ++i) {
73+
glBindBuffer(GL_SHADER_STORAGE_BUFFER, cellsBuffer[i]);
74+
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(int) * gridSize, nullptr, GL_DYNAMIC_COPY);
75+
}
76+
}
77+
78+
void GPUAutomaton::DispatchCompute() {
79+
glUseProgram(computeProgram);
80+
glUniform2i(glGetUniformLocation(computeProgram, "gridSize"), gridWidth, gridHeight);
81+
82+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cellsBuffer[bufferIndex]); // Èñïîëüçóåì òåêóùèé áóôåð
83+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, cellsBuffer[(bufferIndex + 1) % 2]); // Ñëåäóþùèé áóôåð äëÿ îáíîâëåíèÿ
84+
85+
glDispatchCompute(gridWidth, gridHeight, 1);
86+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
87+
88+
// Ïåðåêëþ÷àåì áóôåðû äëÿ ñëåäóþùåãî öèêëà
89+
bufferIndex = (bufferIndex + 1) % 2;
90+
}
91+
92+
void GPUAutomaton::Update() {
93+
// Ñìåíà áóôåðîâ äëÿ äâîéíîé áóôåðèçàöèè
94+
int currentBuffer = bufferIndex;
95+
bufferIndex = (bufferIndex + 1) % 2;
96+
97+
glUseProgram(computeProgram);
98+
glUniform2i(glGetUniformLocation(computeProgram, "gridSize"), gridWidth, gridHeight);
99+
100+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, cellsBuffer[currentBuffer]);
101+
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, cellsBuffer[bufferIndex]);
102+
103+
glDispatchCompute(gridWidth, gridHeight, 1);
104+
glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT);
105+
}
106+
107+
void GPUAutomaton::GetGridState(std::vector<int>& outState) {
108+
outState.resize(gridSize);
109+
glBindBuffer(GL_SHADER_STORAGE_BUFFER, cellsBuffer[bufferIndex]);
110+
glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * gridSize, outState.data());
111+
}
112+
113+
void GPUAutomaton::SetGridState(const std::vector<int>& inState) {
114+
glBindBuffer(GL_SHADER_STORAGE_BUFFER, cellsBuffer[bufferIndex]);
115+
glBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(int) * gridSize, inState.data());
116+
}
117+
118+
119+
void GPUAutomaton::CheckShaderCompilation(GLuint shader, const std::string& name) {
120+
GLint success;
121+
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
122+
if (!success) {
123+
char infoLog[512];
124+
glGetShaderInfoLog(shader, 512, NULL, infoLog);
125+
std::cout << "ERROR::SHADER::" << name << "::COMPILATION_FAILED\n" << infoLog << std::endl;
126+
}
127+
}
128+
129+
void GPUAutomaton::CheckProgramLinking(GLuint program) {
130+
GLint success;
131+
glGetProgramiv(program, GL_LINK_STATUS, &success);
132+
if (!success) {
133+
char infoLog[512];
134+
glGetProgramInfoLog(program, 512, NULL, infoLog);
135+
std::cout << "ERROR::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
136+
}
137+
}

game/GPUAutomaton.h

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//#include <GL/glew.h>
2+
#include "../system/GLFunctions.h"
3+
#include <vector>
4+
5+
class GPUAutomaton {
6+
private:
7+
GLuint computeProgram;
8+
GLuint cellsBuffer[2]; // Äâà áóôåðà äëÿ äâîéíîé áóôåðèçàöèè
9+
GLint bufferIndex; // Èíäåêñ òåêóùåãî áóôåðà (0 èëè 1)
10+
int gridWidth, gridHeight;
11+
int gridSize;
12+
13+
void CreateComputeShader();
14+
void SetupBuffers();
15+
void DispatchCompute();
16+
17+
void CheckShaderCompilation(GLuint shader, const std::string& name);
18+
void CheckProgramLinking(GLuint program);
19+
public:
20+
GPUAutomaton(int width, int height);
21+
~GPUAutomaton();
22+
void Update(); // Ìåòîä äëÿ îáíîâëåíèÿ ìèðà
23+
void GetGridState(std::vector<int>& outState); // Ìåòîä äëÿ èçâëå÷åíèÿ òåêóùåãî ñîñòîÿíèÿ ñåòêè
24+
void SetGridState(const std::vector<int>& inState); // Ìåòîä äëÿ óñòàíîâêè íà÷àëüíîãî ñîñòîÿíèÿ ñåòêè
25+
};

game/GameController.cpp

+82-80
Original file line numberDiff line numberDiff line change
@@ -163,84 +163,84 @@ bool GameController::getCellState(int x, int y) const {
163163
return grid.getCellState(x, y);
164164
}
165165

166-
void GameController::saveGameState(const std::string& filename) {
167-
std::ofstream file(filename);
168-
if (file.is_open()) {
169-
for (int y = 0; y < grid.getHeight(); ++y) {
170-
for (int x = 0; x < grid.getWidth(); ++x) {
171-
file << (grid.getCellState(x, y) ? "1" : "0");
172-
}
173-
file << '\n'; // Íîâàÿ ñòðîêà äëÿ ñëåäóþùåãî ðÿäà
174-
}
175-
file.close();
176-
}
177-
else {
178-
std::cerr << "Íå óäàëîñü îòêðûòü ôàéë äëÿ çàïèñè" << std::endl;
179-
}
180-
}
181-
182-
void GameController::loadGameState(const std::string& filename) {
183-
std::ifstream file(filename);
184-
if (file.is_open()) {
185-
std::string line;
186-
int y = 0;
187-
while (std::getline(file, line) && y < grid.getHeight()) {
188-
for (int x = 0; x < std::min(static_cast<int>(line.length()), grid.getWidth()); ++x) {
189-
grid.setCellState(x, y, line[x] == '1');
190-
}
191-
++y;
192-
}
193-
file.close();
194-
}
195-
else {
196-
std::cerr << "Íå óäàëîñü îòêðûòü ôàéë äëÿ ÷òåíèÿ" << std::endl;
197-
}
198-
}
199-
200-
void GameController::saveGameStateCSV(const std::string& filename) {
201-
std::ofstream file(filename);
202-
if (file.is_open()) {
203-
for (int y = 0; y < grid.getHeight(); ++y) {
204-
for (int x = 0; x < grid.getWidth(); ++x) {
205-
const Cell& cell = grid.getCell(x, y);
206-
file << (cell.getAlive() ? "1" : "0") << ","
207-
<< cell.getType() << ","
208-
<< cell.getColor().X() << ","
209-
<< cell.getColor().Y() << ","
210-
<< cell.getColor().Z();
211-
if (x < grid.getWidth() - 1) file << ";"; // Ðàçäåëèòåëü ìåæäó êëåòêàìè â ñòðîêå
212-
}
213-
file << '\n'; // Íîâàÿ ñòðîêà äëÿ ñëåäóþùåãî ðÿäà
214-
}
215-
file.close();
216-
}
217-
}
218-
219-
void GameController::loadGameStateCSV(const std::string& filename) {
220-
std::ifstream file(filename);
221-
if (file.is_open()) {
222-
std::string line, cellData;
223-
int y = 0;
224-
while (std::getline(file, line) && y < grid.getHeight()) {
225-
std::istringstream iss(line);
226-
for (int x = 0; x < grid.getWidth(); ++x) {
227-
if (std::getline(iss, cellData, ';')) {
228-
std::istringstream cellStream(cellData);
229-
bool isAlive; int type; float r, g, b;
230-
char comma;
231-
if (cellStream >> isAlive >> comma >> type >> comma >> r >> comma >> g >> comma >> b) {
232-
Cell& cell = grid.getCell(x, y);
233-
cell.setAlive(isAlive);
234-
cell.setType(type);
235-
cell.setColor(Vector3d(r, g, b));
236-
}
237-
}
238-
}
239-
++y;
240-
}
241-
file.close();
242-
}
243-
}
166+
//void GameController::saveGameState(const std::string& filename) {
167+
// std::ofstream file(filename);
168+
// if (file.is_open()) {
169+
// for (int y = 0; y < grid.getHeight(); ++y) {
170+
// for (int x = 0; x < grid.getWidth(); ++x) {
171+
// file << (grid.getCellState(x, y) ? "1" : "0");
172+
// }
173+
// file << '\n'; // Íîâàÿ ñòðîêà äëÿ ñëåäóþùåãî ðÿäà
174+
// }
175+
// file.close();
176+
// }
177+
// else {
178+
// std::cerr << "Íå óäàëîñü îòêðûòü ôàéë äëÿ çàïèñè" << std::endl;
179+
// }
180+
//}
181+
182+
//void GameController::loadGameState(const std::string& filename) {
183+
// std::ifstream file(filename);
184+
// if (file.is_open()) {
185+
// std::string line;
186+
// int y = 0;
187+
// while (std::getline(file, line) && y < grid.getHeight()) {
188+
// for (int x = 0; x < std::min(static_cast<int>(line.length()), grid.getWidth()); ++x) {
189+
// grid.setCellState(x, y, line[x] == '1');
190+
// }
191+
// ++y;
192+
// }
193+
// file.close();
194+
// }
195+
// else {
196+
// std::cerr << "Íå óäàëîñü îòêðûòü ôàéë äëÿ ÷òåíèÿ" << std::endl;
197+
// }
198+
//}
199+
200+
//void GameController::saveGameStateCSV(const std::string& filename) {
201+
// std::ofstream file(filename);
202+
// if (file.is_open()) {
203+
// for (int y = 0; y < grid.getHeight(); ++y) {
204+
// for (int x = 0; x < grid.getWidth(); ++x) {
205+
// const Cell& cell = grid.getCell(x, y);
206+
// file << (cell.getAlive() ? "1" : "0") << ","
207+
// << cell.getType() << ","
208+
// << cell.getColor().X() << ","
209+
// << cell.getColor().Y() << ","
210+
// << cell.getColor().Z();
211+
// if (x < grid.getWidth() - 1) file << ";"; // Ðàçäåëèòåëü ìåæäó êëåòêàìè â ñòðîêå
212+
// }
213+
// file << '\n'; // Íîâàÿ ñòðîêà äëÿ ñëåäóþùåãî ðÿäà
214+
// }
215+
// file.close();
216+
// }
217+
//}
218+
219+
//void GameController::loadGameStateCSV(const std::string& filename) {
220+
// std::ifstream file(filename);
221+
// if (file.is_open()) {
222+
// std::string line, cellData;
223+
// int y = 0;
224+
// while (std::getline(file, line) && y < grid.getHeight()) {
225+
// std::istringstream iss(line);
226+
// for (int x = 0; x < grid.getWidth(); ++x) {
227+
// if (std::getline(iss, cellData, ';')) {
228+
// std::istringstream cellStream(cellData);
229+
// bool isAlive; int type; float r, g, b;
230+
// char comma;
231+
// if (cellStream >> isAlive >> comma >> type >> comma >> r >> comma >> g >> comma >> b) {
232+
// Cell& cell = grid.getCell(x, y);
233+
// cell.setAlive(isAlive);
234+
// cell.setType(type);
235+
// cell.setColor(Vector3d(r, g, b));
236+
// }
237+
// }
238+
// }
239+
// ++y;
240+
// }
241+
// file.close();
242+
// }
243+
//}
244244

245245
void GameController::resizeGrid(int newWidth, int newHeight) {
246246
if (newWidth <= 0 || newHeight <= 0) return; // Ïðîâåðêà íà ïîëîæèòåëüíûé ðàçìåð
@@ -249,8 +249,10 @@ void GameController::resizeGrid(int newWidth, int newHeight) {
249249
Grid newGrid(newWidth, newHeight);
250250

251251
// Êîïèðóåì ñòàðûå äàííûå â íîâóþ ñåòêó, ãäå ýòî âîçìîæíî
252-
for (int y = 0; y < std::min(grid.getHeight(), newHeight); ++y) {
253-
for (int x = 0; x < std::min(grid.getWidth(), newWidth); ++x) {
252+
for (int y = 0; y < grid.getHeight(); ++y) {
253+
if (y >= newHeight) break; // Âûõîäèì èç öèêëà, åñëè ïðåâûøàåì íîâóþ âûñîòó
254+
for (int x = 0; x < grid.getWidth(); ++x) {
255+
if (x >= newWidth) break; // Âûõîäèì èç öèêëà, åñëè ïðåâûøàåì íîâóþ øèðèíó
254256
newGrid.setCellState(x, y, grid.getCellState(x, y));
255257
}
256258
}

game/GameController.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ class GameController {
184184
bool getCellState(int x, int y) const;
185185
const Grid& getGrid() const { return grid; }
186186

187-
void saveGameState(const std::string& filename);
188-
void loadGameState(const std::string& filename);
189-
void saveGameStateCSV(const std::string& filename);
190-
void loadGameStateCSV(const std::string& filename);
187+
//void saveGameState(const std::string& filename);
188+
//void loadGameState(const std::string& filename);
189+
//void saveGameStateCSV(const std::string& filename);
190+
//void loadGameStateCSV(const std::string& filename);
191191

192192
// ìåòîä äëÿ èçìåíåíèÿ ðàçìåðà ñåòêè
193193
void resizeGrid(int newWidth, int newHeight);

0 commit comments

Comments
 (0)