From 990bd319c696c2b65fa858b40fd75279fec2a13b Mon Sep 17 00:00:00 2001 From: Fox Caminiti Date: Fri, 18 Nov 2022 23:40:08 -0500 Subject: txt2img functional --- build.sh | 2 +- createcalls.cpp | 2 +- defines.h | 4 +- functions.h | 2 +- lib/base64.c | 11 ++- main.cpp | 54 +++++++++-- main.h | 9 ++ memory.cpp | 179 +++++++------------------------------ my_imgui_widgets.cpp | 74 ++++++++++----- stable_diffusion.cpp | 248 +++++++++++++++++++++++++++++++++++++++++++++++++-- stable_diffusion.h | 15 +++- undo.cpp | 48 +--------- 12 files changed, 405 insertions(+), 243 deletions(-) diff --git a/build.sh b/build.sh index 1e4f865..e0df0d4 100755 --- a/build.sh +++ b/build.sh @@ -118,7 +118,7 @@ clang lib/glad.c $GLAD_FLAGS -I/usr/local/include -I/opt/local/include -c \ $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/glad.o clang main.cpp $WARNING_FLAGS $OPTIMIZATION $ADDITIONAL_FLAGS -o bin/real2d bin/*.o \ $GLAD_FLAGS \ - -std=c++11 -lstdc++ -Iimgui -Iimgui/backends \ + -std=c++11 -lstdc++ -lcurl -Iimgui -Iimgui/backends \ $SDL_ARGS \ -I . \ -lm -I /usr/local/include $(pkg-config --cflags --libs $FFMPEG_LIBS) diff --git a/createcalls.cpp b/createcalls.cpp index 85faa3c..e88e39f 100644 --- a/createcalls.cpp +++ b/createcalls.cpp @@ -266,7 +266,7 @@ void Clipboard_Store(project_data *File, project_state *State, memory *Memory, s for (int p = 0; p < Property->Keyframe_Count; p++) { bezier_point *PointAddress = Bezier_LookupAddress(Memory, Property, ArrayLocation[p]); if (PointAddress->IsSelected) { - Arbitrary_WriteInto((uint8 *)PointAddress, (uint8 *)State->ClipboardBuffer + ClipboardPos, sizeof(bezier_point)); + Memory_Copy((uint8 *)State->ClipboardBuffer + ClipboardPos, (uint8 *)PointAddress, sizeof(bezier_point)); ClipboardPos += sizeof(bezier_point); Channel->KeyframeCount++; } diff --git a/defines.h b/defines.h index fd63c30..1e8a933 100644 --- a/defines.h +++ b/defines.h @@ -42,8 +42,8 @@ typedef uint64 ptrsize; // is there a compiler variable for 32 vs 64 bit like #define AmountOf(Array) sizeof((Array)) / sizeof((Array)[1]) #if ARM -#define GetTime() Assert(0) +#define GetCPUTime() Assert(0) #else -#define GetTime() __rdtsc() +#define GetCPUTime() __rdtsc() #endif diff --git a/functions.h b/functions.h index a1f5d2a..69ce817 100644 --- a/functions.h +++ b/functions.h @@ -1,6 +1,6 @@ // static bool32 AV_IsFileSupported(char *filename, bool32 *IsVideo); -static void Arbitrary_WriteInto(uint8 *Address_Read, uint8 *Address_Write, uint64 Size); +static void Memory_Copy(uint8 *Address_Write, uint8 *Address_Read, uint64 Size); static void Arbitrary_Zero(uint8 *Address_Write, uint64 Size); static void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size); static void Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction); diff --git a/lib/base64.c b/lib/base64.c index 1e7e192..b6a8e5d 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -1,3 +1,5 @@ +// Slightly moulded by Fox to better suit his (poor?) tastes. + /* The compilation of software known as FreeBSD is distributed under the following terms: @@ -122,7 +124,7 @@ void base64_encode(const unsigned char *src, size_t len, * Caller is responsible for freeing the returned buffer. */ unsigned char * base64_decode(const unsigned char *src, size_t len, - size_t *out_len) + unsigned char *out_buffer, size_t *out_len) { unsigned char dtable[256], *out, *pos, block[4], tmp; size_t i, count, olen; @@ -148,11 +150,8 @@ unsigned char * base64_decode(const unsigned char *src, size_t len, return NULL; olen = count / 4 * 3; - // pos = out = os_malloc(olen); - pos = out = NULL; - Assert(0); - if (out == NULL) - return NULL; + pos = out = out_buffer; + Assert(out != NULL) count = 0; for (i = 0; i < len; i++) { diff --git a/main.cpp b/main.cpp index 85dd002..3cc976c 100644 --- a/main.cpp +++ b/main.cpp @@ -33,6 +33,8 @@ #define STBI_FAILURE_USERMSG #include "lib/stb_image.h" +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "lib/stb_image_write.h" #include "defines.h" #include "my_math.h" @@ -60,6 +62,7 @@ static instruction_mode InstructionMode = instruction_mode_scalar; static uint32 RandomGlobalIncrement = 0; #include "lib/base64.c" +#include #include "memory.cpp" #include "undo.cpp" @@ -242,7 +245,8 @@ Main_InputTest(project_data *File, project_state *State, memory *Memory, ui *UI, ImGui_File(File, State, Memory, io, Sorted.CompArray, Sorted.LayerArray); ImGui_PropertiesPanel(File, State, UI, Memory, io); ImGui_ColorPanel(File, State, UI, Memory, io); - ImGui_StableDiffusion(File, State, UI, Memory, io); + ImGui_SD_Prompt(File, State, UI, Memory, io); + ImGui_SD_Thumbnail(File, State, UI, Memory, io); ImGui_Menu(File, State, UI, Memory, io); File_Sort_Pop(Memory, Sorted.Layer_SortSize, Sorted.Property_SortSize); @@ -281,7 +285,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io // if (Entry_Main->IsCached) // return CompBuffer; - uint64 Comp_TimeStart = GetTime(); + uint64 Comp_TimeStart = GetCPUTime(); sorted_comp_info *SortedCompInfo = &SortedCompArray[CompIndex]; sorted_layer *SortedLayerInfo = Layer_GetSortedArray(SortedLayerArray, SortedCompArray, CompIndex); @@ -356,7 +360,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io } else { cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0); if (!Entry->IsCached) { - uint64 Src_TimeStart = GetTime(); + uint64 Src_TimeStart = GetCPUTime(); block_string *Name = (block_string *)Memory_Block_AddressAtIndex(Memory, F_Strings, Source->Path_String_Index); int w = 0, h = 0; void *temp = stbi_load(Name->Char, &w, &h, NULL, 4); @@ -365,11 +369,11 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io Source->BytesPerPixel = 4; uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel; void *Source_Address = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); - Arbitrary_WriteInto((uint8 *)temp, (uint8 *)Source_Address, Size); + Memory_Copy((uint8 *)Source_Address, (uint8 *)temp, Size); stbi_image_free(temp); BitmapState->ToUpdate = false; BitmapState->CurrentFrame = 0; - Entry->CycleTime = GetTime() - Src_TimeStart; + Entry->CycleTime = GetCPUTime() - Src_TimeStart; Layer->x.CurrentValue = Comp->Width/2; Layer->y.CurrentValue = Comp->Height/2; Entry->IsCached = true; @@ -405,7 +409,7 @@ Render_Comp(project_data *File, project_state *State, memory *Memory, ImGuiIO io Render_Main((void *)&T, CompBuffer, render_type_main, RenderRegion); } } - Entry_Main->CycleTime = GetTime() - Comp_TimeStart; + Entry_Main->CycleTime = GetCPUTime() - Comp_TimeStart; Entry_Main->IsCached = true; return CompBuffer; } @@ -503,6 +507,9 @@ int main(int argc, char *argv[]) { State->Brush.TransientBitmap = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); ScratchPaintSize = 2048*2048*4; Memory.ScratchPos += ScratchPaintSize; + State->Dump1 = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); + Memory.ScratchPos += ScratchPaintSize; + State->Dump2 = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); State->ClipboardBuffer = (void *)((uint8 *)Memory.Slot[B_ScratchSpace].Address + Memory.ScratchPos); State->ClipboardSize = 1024*1024; @@ -852,12 +859,47 @@ int main(int argc, char *argv[]) { Brush_CalcBitmapAlphaFromSize(&Memory, &State->Brush, 4); State_BindBrushTexture(&Memory, &State->Brush, 4); + curl_global_init(CURL_GLOBAL_ALL); + curl_state MainHandle = {}; + curl_state ProgHandle = {}; + uint32 Inc = 0; while (State->IsRunning) { // State->Interact_Active = interact_type_layer_move; // State->Interact_Offset[1] = -3.0f; + if (State->CurlActive) { + if (State->CurlActive == -1) { + Curl_GET_Init(&MainHandle, State->Dump1, State->JSONPayload, State->SD.ServerAddress, State->SD.Mode); + Curl_Prog_Init(&ProgHandle, State->Dump2); + State->CurlActive = 1; + } else { + if (Curl_Check(&MainHandle) == 1) { + SD_JSONToSource(File, State, &Memory, State->Dump1, State->SD.Height, State->SD.Width); + Curl_Free(&ProgHandle); + curl_slist_free_all(ProgHandle.list); + Curl_Free(&MainHandle); + State->CurlActive = 0; + } + uint64 Time = ImGui::GetTime(); + if (Time - State->SDTimer > 0.3f) { + if (Curl_Check(&ProgHandle) == 1) { + SD_ParseProgress(State, (char *)State->Dump2); + curl_multi_remove_handle(ProgHandle.curlm, ProgHandle.curl); + curl_easy_reset(ProgHandle.curl); + ProgHandle.CurlData.size = 0; + curl_easy_setopt(ProgHandle.curl, CURLOPT_URL, "http://127.0.0.1:7860/sdapi/v1/progress"); + curl_easy_setopt(ProgHandle.curl, CURLOPT_WRITEFUNCTION, dumbcurlcallback); + curl_easy_setopt(ProgHandle.curl, CURLOPT_WRITEDATA, (void *)&ProgHandle.CurlData); + curl_multi_add_handle(ProgHandle.curlm, ProgHandle.curl); + } + State->SDTimer = Time; + } + Inc++; + } + } + Main_InputTest(File, State, &Memory, &UI, window, textureID); if (State->IsPlaying) { diff --git a/main.h b/main.h index e0a9374..3d7b3e5 100644 --- a/main.h +++ b/main.h @@ -315,6 +315,14 @@ struct project_state brush_state Brush; sd_state SD; + char JSONPayload[1024]; + int32 CurlActive = 0; + real32 SDPercentDone; + real32 SDTimeEstimate; + real64 SDTimer; + + void *Dump1; + void *Dump2; char DummyName2[512]; @@ -369,6 +377,7 @@ struct block_composition enum source_type { source_type_none, source_type_principal, + source_type_principal_temp, source_type_file }; diff --git a/memory.cpp b/memory.cpp index 4593d49..64aadc1 100644 --- a/memory.cpp +++ b/memory.cpp @@ -1,3 +1,4 @@ + static void Memory_InitTable(global_memory *GlobalMemory, memory *Memory, uint64 Size, memory_table_list TableName, char *Name, uint64 Block_ElementSize = 0) { memory_table *Table = &Memory->Slot[TableName]; @@ -250,166 +251,48 @@ Memory_AddressAtOffset(memory *Memory, memory_table_list TableName, uint64 Offse return (void *)((uint8 *)Table->Address + Offset); } -#if 0 -static void* -AllocateMemory(memory *Memory, uint64 Size, memory_table_list TableName) { - void *Address; - memory_table *Table = &Memory->Slot[TableName]; - if (Table->CurrentPosition + Size > Table->Size) { - return NULL; - } - Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition); - Table->CurrentPosition += Size; - return Address; -} - -// Returns the address without advancing -static void* -Memory_GetAddressAt(memory *Memory, uint64 Size, memory_table_list TableName) { - void *Address; - memory_table *Table = &Memory->Slot[TableName]; - if (Table->CurrentPosition + Size > Table->Size) { - return NULL; +void Memory_Copy(uint8 *Address_Write, uint8 *Address_Read, uint64 Size) +{ + uint64 i = 0; + while (i < Size) { + *(Address_Write + i) = *(Address_Read + i); + i++; } - Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition + Size); - return Address; -} - -// Returns the address and THEN advances -static void* -Memory_Advance(memory *Memory, uint64 Size, memory_table_list TableName) { - return AllocateMemory(Memory, Size, TableName); } -// Rewinds and THEN returns the address -static void* -Memory_Rewind(memory *Memory, uint64 Size, memory_table_list TableName) { - void *Address; - memory_table *Table = &Memory->Slot[TableName]; - if (Table->CurrentPosition - Size < 0) { - return NULL; +void Arbitrary_Zero(uint8 *Address_Write, uint64 Size) +{ + uint64 i = 0; + while (i < Size) { + *(Address_Write + i) = 0; + i++; } - Table->CurrentPosition -= Size; - Address = (ptrsize *)((uint8 *)Table->Address + Table->CurrentPosition); - return Address; } -// Returns 0-1 range wherever Pointer is in relation to StartingPointer to Size*Amount. -static real32 -Memory_NormalizedPosition(void *StartingPointer, uint32 Amount, uint32 Size, void *Pointer) +void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size) { - real32 Result = 0; - uint64 TotalSize = Amount*Size; - uint64 PointerLocationSize = (uint8 *)Pointer - (uint8 *)StartingPointer; - Result = (real32)PointerLocationSize / (real32)TotalSize; - return Result; + uint8 *Buffer_Scratch = (uint8 *)Memory_PushScratch(Memory, Size); + Memory_Copy(Buffer_Scratch, Address_0, Size); + Memory_Copy(Address_0, Address_1, Size); + Memory_Copy(Address_1, Buffer_Scratch, Size); + Memory_PopScratch(Memory, Size); } -static void -Debug_Memory_Assert_Cohesion(memory *Memory, memory_table *Table) -{ -#if DEBUG - for (uint32 i = 0; i < Table->NumberOfPointers; i++) { - cached_bitmap *CurrentBitmap = &Memory->Bitmap[i]; - Assert(CurrentBitmap->Data); - for (uint32 a = 0; a < Table->NumberOfPointers; a++) { - if (a == i) { - continue; - } - cached_bitmap *OtherBitmap = &Memory->Bitmap[a]; - if (OtherBitmap->Data == CurrentBitmap->Data) { - Assert(0); - } - } - } -#else -#endif -} -static cached_bitmap * -Memory_RollingBitmap(memory *Memory, source *Source, uint32 FrameToSeek) +static void +Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction) { - uint16 Width = Source->Info.Width; - uint16 Height = Source->Info.Height; - uint16 BytesPerPixel = Source->Info.BytesPerPixel; - - memory_table *Table = &Memory->Slot[B_LoadedBitmaps]; - - // First check whether we'd run over the buffer at the current - // position, and reset the position if so. - uint64 Size = Bitmap_CalcTotalBytes(Width, Height, BytesPerPixel); - if (Table->CurrentPosition + Size > Table->Size) { - Table->CurrentPosition = 0; - Table->PointerIndex = 0; - } - - cached_bitmap *Bitmap = &Memory->Bitmap[Table->PointerIndex]; - - // If there are no pointers in front of us, we don't have to free any space - // and just need to increment the number of pointers. - if (Table->PointerIndex != Table->NumberOfPointers) { - // Next, if there's a pointer in front of the current position, - // check whether it's far away enough so that the size fits. - bool32 BS = true; - if (Bitmap->Data) { - uint64 BytesBetween = (uint8 *)Bitmap->Data - ((uint8 *)Table->Address + Table->CurrentPosition); - if (BytesBetween > Size) { - uint32 StopAt = Table->NumberOfPointers - 1; - while (StopAt > Table->PointerIndex - 1) { - Memory->Bitmap[StopAt + 1] = Memory->Bitmap[StopAt]; - StopAt--; - } - Table->NumberOfPointers++; - BS = false; - } - } - // If it doesn't fit, then we need to dereference the pointers - // until we have enough space. - if ((Table->PointerIndex < Table->NumberOfPointers) && BS) - { - bool32 Avail = false; - void *AddressStart = (void *)((uint8 *)Table->Address + Table->CurrentPosition); - uint32 Amount = 0; - while(!Avail) { - // Bail out if we're on the last index, as we don't need to do anything else. - // TODO(fox): This could be simplified if we compared - // pointer start plus data instead of just the start. - if (Table->PointerIndex != Table->NumberOfPointers - 1) { - void *Data2 = Memory->Bitmap[Table->PointerIndex+1].Data; - uint64 BytesBetween = (uint8 *)Data2 - (uint8 *)AddressStart; - if (BytesBetween < Size) { - uint32 StopAt = Table->PointerIndex; - while (StopAt < Table->NumberOfPointers - 1) { - Memory->Bitmap[StopAt] = Memory->Bitmap[StopAt + 1]; - StopAt++; - } - Amount++; - Table->NumberOfPointers--; - if (Amount > 2) { - Amount += 0; - } - } else { - Avail = true; - } - } else { - Avail = true; - } - } + if (Direction > 0) { + uint8 *AddressPlayhead = Address_End; + while ((ptrsize)AddressPlayhead >= (ptrsize)Address_Start) { + *(AddressPlayhead + ShiftAmount) = *AddressPlayhead; + AddressPlayhead--; } } else { - Table->NumberOfPointers++; - } - Bitmap->Data = AllocateMemory(Memory, Size, B_LoadedBitmaps); - if (!Bitmap->Data) { - Assert(0); + uint8 *AddressPlayhead = Address_Start; + while ((ptrsize)AddressPlayhead < (ptrsize)Address_End) { + *(AddressPlayhead - ShiftAmount) = *AddressPlayhead; + AddressPlayhead++; + } } - Bitmap->SourceOwner = Source; - Bitmap->Frame = FrameToSeek; - Table->PointerIndex++; - - // No two pointers on the table should hold the same data - // address or be empty. - Debug_Memory_Assert_Cohesion(Memory, Table); - return Bitmap; } -#endif diff --git a/my_imgui_widgets.cpp b/my_imgui_widgets.cpp index bfe114b..b3339d2 100644 --- a/my_imgui_widgets.cpp +++ b/my_imgui_widgets.cpp @@ -35,7 +35,7 @@ ImGui_PropertiesPanel(project_data *File, project_state *State, ui *UI, memory * bool32 Display = 1; block_layer *Layer = NULL; if (State->MostRecentlySelectedLayer > -1) { - Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->MostRecentlySelectedLayer); + Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, State->MostRecentlySelectedLayer, 0); if (!Layer->Occupied) Display = 0; } else { @@ -237,28 +237,57 @@ ImGui_File(project_data *File, project_state *State, memory *Memory, ImGuiIO io, } static void -ImGui_StableDiffusion(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) +ImGui_SD_Thumbnail(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) +{ + ImGui::Begin("SD gallery"); + ImGui::End(); +} + +static void +ImGui_SD_Prompt(project_data *File, project_state *State, ui *UI, memory *Memory, ImGuiIO io) { ImGui::Begin("SD prompt input"); sd_state *SD = &State->SD; int Size = ImGui::GetFontSize(); ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(200, 80, 0, 255)); if (ImGui::Button("Generate!", ImVec2(Size*8, Size*2))) { - /* - block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); - block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); - cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0); - Assert(Entry->IsCached); - void *BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); - uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel; - uint64 EncodedLength = 0; - uint64 EncodedAllocSize = base64_encode_size(Size); - void *EncodedOutput = Memory_PushScratch(Memory, EncodedSize); - uint64 EncodedTrueSize; - base64_encode((uint8 *)BitmapAddress, Size, (uint8 *)EncodedOutput, &EncodedTrueSize); - Memory_PopScratch(Memory, EncodedSize); - */ - SD_Txt2Txt(SD); + if (!State->CurlActive) { + if (SD->Mode) { + block_layer *Layer = (block_layer *)Memory_Block_AddressAtIndex(Memory, F_Layers, 0); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, Layer->Block_Source_Index); + cache_entry *Entry = Memory_Cache_Search(State, Memory, cache_entry_type_source, Layer->Block_Source_Index, 0); + Assert(Entry->IsCached); + void *BitmapAddress = Memory_Block_Bitmap_AddressAtIndex(Memory, Entry->Block_StartIndex); + uint64 Size = Source->Width * Source->Height * Source->BytesPerPixel; + + int32 len = 0; + uint8 *PNGBitmap = stbi_write_png_to_mem((uint8 *)BitmapAddress, Source->Width * Source->BytesPerPixel, + Source->Width, Source->Height, Source->BytesPerPixel, &len); + Assert(PNGBitmap); + + uint64 EncodedLength = 0; + uint64 EncodedAllocSize = base64_encode_size(Size); + uint8 *EncodedOutput = (uint8 *)Memory_PushScratch(Memory, EncodedAllocSize); + uint64 EncodedTrueSize; + + base64_encode((uint8 *)BitmapAddress, Size, EncodedOutput, &EncodedTrueSize); + Assert(EncodedOutput[EncodedTrueSize] == '\0'); + + STBIW_FREE(PNGBitmap); + + SD_AssembleJSON(SD, (char *)State->Dump1, EncodedOutput); + Memory_PopScratch(Memory, EncodedAllocSize); + } else { + SD_AssembleJSON(SD, State->JSONPayload); + // SD_AssembleJSON(SD, (char *)State->Dump2); + } + State->CurlActive = -1; + } + } + ImGui::PopStyleColor(); + if (State->CurlActive) { + ImGui::SameLine(); + ImGui::Text("Est. time: %.1f sec, %.2f", State->SDTimeEstimate, State->SDPercentDone*100); } ImGui::InputText("Address", SD->ServerAddress, SD_LEN_ADDRESS); if (State->Initializing && (SD->ServerAddress[0] == '\0')) { @@ -266,7 +295,10 @@ ImGui_StableDiffusion(project_data *File, project_state *State, ui *UI, memory * sprintf(SD->NegPrompt, "%s", "nsfw, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark"); sprintf(SD->ServerAddress, "%s", "http://127.0.0.1:7860"); } - ImGui::PopStyleColor(); + if (ImGui::Selectable("txt2img", !SD->Mode)) + SD->Mode = 0; + if (ImGui::Selectable("img2img", SD->Mode)) + SD->Mode = 1; ImGui::InputTextMultiline("Prompt", SD->Prompt, SD_LEN_PROMPT); ImGui::InputTextMultiline("Negative prompt", SD->NegPrompt, SD_LEN_PROMPT); ImGui::SliderInt("Steps", &SD->Steps, 0, 150); @@ -279,7 +311,9 @@ ImGui_StableDiffusion(project_data *File, project_state *State, ui *UI, memory * SD->Height = SD->Height + (64 - (SD->Height % 64)); } ImGui::SliderFloat("CFG scale", &SD->CFG, 1, 30, "%.2f"); - ImGui::SliderFloat("Denoising strength", &SD->DenoisingStrength, 0, 1, "%.2f"); + if (SD->Mode) { + ImGui::SliderFloat("Denoising strength", &SD->DenoisingStrength, 0, 1, "%.2f"); + } ImGui::InputInt("Seed", &SD->Seed); ImGui::End(); } @@ -840,7 +874,7 @@ ImGui_Viewport(project_data *File, project_state *State, ui *UI, memory *Memory, ImGui::InvisibleButton("canvas", ViewportScale, ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight); bool32 IsHovered = ImGui::IsItemHovered(); -#if 0 +#if 1 bool32 IsActive = ImGui::IsItemActive(); bool32 IsActivated = ImGui::IsItemActivated(); #else diff --git a/stable_diffusion.cpp b/stable_diffusion.cpp index 0c42f03..2eb230b 100644 --- a/stable_diffusion.cpp +++ b/stable_diffusion.cpp @@ -1,15 +1,121 @@ +struct curl_data { + char *response; + size_t size; +}; + +static size_t dumbcurlcallback(void *data, size_t size, size_t nmemb, void *userp) + { + size_t realsize = size * nmemb; + curl_data *mem = (curl_data *)userp; + + Memory_Copy((uint8 *)&(mem->response[mem->size]), (uint8 *)data, realsize); + mem->size += realsize; + mem->response[mem->size] = 0; + + return realsize; + } + +static void +SD_JSONToSource(project_data *File, project_state *State, memory *Memory, void *JSONResponse, int Height, int Width) +{ + // We've gotta go from base64 to compressed PNG to the raw format we want. + uint8 *Data = (uint8 *)JSONResponse; + uint64 i = 0; + Assert(Data[2] != 'd'); + while (Data[i] != '[') + i++; + i += 2; + Assert(Data[i] != '"'); + uint64 UncompressedSize = Width * Height * 4; + uint64 c = 0; + while (Data[i+c] != ']') + c++; + uint64 MaxSize = Width * Height * 4; + void *PNGData = Memory_PushScratch(Memory, MaxSize); + uint64 PNGSize = 0; + base64_decode(&Data[i], c, (uint8 *)PNGData, &PNGSize); + int x, y, a; + void *RawData = stbi_load_from_memory((stbi_uc *)PNGData, PNGSize, &x, &y, &a, 4); + Assert(x == Width && y == Height); + Memory_PopScratch(Memory, MaxSize); + int SrcIdx = Source_Generate_Blank(File, State, Memory, Width, Height, 4); + block_source *Source = (block_source *)Memory_Block_AddressAtIndex(Memory, F_Sources, SrcIdx); + // Source->Type = source_type_principal_temp; + void *BitmapAddress = Memory_Block_AddressAtIndex(Memory, F_PrincipalBitmaps, Source->Bitmap_Index, 0); + Memory_Copy((uint8 *)BitmapAddress, (uint8 *)RawData, MaxSize); + stbi_image_free(RawData); +} static void -SD_Txt2Txt(sd_state *SD) +SD_ParseProgress(project_state *State, char *JSONInfo) { - char JSONPayload[1024]; - char CurlCommand[1024]; + char P[4]; + char P2[8]; + int ProgLocation = 0; + while (!(JSONInfo[ProgLocation] == 's' && JSONInfo[ProgLocation+1] == 's')) { + ProgLocation++; + } + ProgLocation += 4; + int ETALocation = ProgLocation; + while (!(JSONInfo[ETALocation] == 'v' && JSONInfo[ETALocation+1] == 'e')) { + ETALocation++; + } + ETALocation += 4; + // Assert(JSONInfo[ProgLocation] >= '0' && JSONInfo[ProgLocation] <= '9'); + // Assert(JSONInfo[ETALocation] >= '0' && JSONInfo[ETALocation] <= '9'); + Memory_Copy((uint8 *)P, (uint8 *)&JSONInfo[12], 4); + Memory_Copy((uint8 *)P2, (uint8 *)&JSONInfo[32], 8); + real32 Percent = atof(P); + if (Percent > 0.0f) // occasionally returns negative + State->SDPercentDone = Percent; + real32 Time = atof(P2); + if (Time > 0.1f) // occasionally returns zero for some reason + State->SDTimeEstimate = Time; + // Assert(0); +} + +static void +JSON_AppendParam_String(char *String, uint64 *i, char *P1, char *P2) +{ + uint64 c = *i; + String[c++] = '"'; + int a = 0; + while(P1[a] != '\0') { + String[c++] = P1[a++]; + } + String[c++] = ':'; + String[c++] = ' '; + String[c++] = '"'; + a = 0; + while(P2[a] != '\0') { + String[c++] = P2[a++]; + if (a > 64) + break; + } + c--; + String[c++] = '"'; + String[c++] = ','; + String[c++] = '\n'; + String[c++] = '\0'; + *i = c; +} + +static void +SD_AssembleJSON(sd_state *SD, char *JSONPayload, void *Base64Bitmap = NULL) +{ + Arbitrary_Zero((uint8 *)JSONPayload, 1024); + // char CurlCommand[1024]; char *Test[] = { "prompt", "negative_prompt", "steps", "width", "height", "cfg_scale" }; void *Test2[6] = { (void *)SD->Prompt, (void *)SD->NegPrompt, (void *)&SD->Steps, (void *)&SD->Width, (void *)&SD->Height, (void *)&SD->CFG }; int Type[6] = { 0, 0, 1, 1, 1, 2}; - sprintf(JSONPayload, "%s{\n", JSONPayload); + JSONPayload[0] = '{'; + JSONPayload[1] = '\n'; + JSONPayload[2] = '\0'; + uint64 i = 2; + if (SD->Mode) + JSON_AppendParam_String(JSONPayload, &i, "init_images", (char *)Base64Bitmap); for (int i = 0; i < 6; i++) { if (Type[i] == 0) { sprintf(JSONPayload, "%s\"%s\": \"%s\",\n", JSONPayload, Test[i], (char *)Test2[i]); @@ -21,8 +127,136 @@ SD_Txt2Txt(sd_state *SD) Assert(0); } } + if (SD->Mode) + sprintf(JSONPayload, "%s\"%s\": %.2f,\n", JSONPayload, "denoising_strength", SD->DenoisingStrength); + sprintf(JSONPayload, "%s%s\n", JSONPayload, "\"sampler_index\": \"DDIM\""); sprintf(JSONPayload, "%s}\n", JSONPayload); - sprintf(CurlCommand, "curl -X POST -H 'Content-Type: application/json' -i '%s/sdapi/v1/txt2img' --data '%s'", - SD->ServerAddress, JSONPayload); - printf("%s\n", CurlCommand); + // sprintf(CurlCommand, "curl -X POST -H 'Content-Type: application/json' -i '%s/sdapi/v1/txt2img' --data '%s'", SD->ServerAddress, JSONPayload); + // printf("%s\n", CurlCommand); }; + +struct curl_state +{ + CURL *curl; + CURLM *curlm; + curl_slist *list = NULL; + curl_data CurlData; +}; + +static void +Curl_Free(curl_state *Handle) +{ + curl_multi_remove_handle(Handle->curlm, Handle->curl); + curl_easy_cleanup(Handle->curl); + curl_multi_cleanup(Handle->curlm); +} + +static bool32 +Curl_Check(curl_state *Handle) +{ + int IsActive; + CURLMcode mc = curl_multi_perform(Handle->curlm, &IsActive); + Assert(!mc); + if (!IsActive) { + int queue = 0; + CURLMsg *msg = curl_multi_info_read(Handle->curlm, &queue); + if (msg) { + CURL *e = msg->easy_handle; + Assert(e == Handle->curl); + Assert(msg->msg == CURLMSG_DONE); + if (!msg->data.result) { + return 1; + } else if (msg->data.result == CURLE_COULDNT_CONNECT) { + // printf("Active stable-diffusion-webui instance not found at URL.\n"); + return -1; + } else { + // printf("curl error: %s!\n", curl_easy_strerror(msg->data.result)); + return -1; + } + } + } + return 0; +} + +static char *APIString[] = {"txt2img", "img2img" }; + +static void +Curl_GET_Init(curl_state *C, void *OutputData, char *JSONPayload, char *IP, bool32 API) +{ + C->list = curl_slist_append(C->list, "Content-Type: application/json"); + + C->curl = curl_easy_init(); + Assert(C->curl); + + char URL[512]; + sprintf(URL, "%s/sdapi/v1/%s", IP, APIString[API]); + curl_easy_setopt(C->curl, CURLOPT_URL, URL); + curl_easy_setopt(C->curl, CURLOPT_HTTPHEADER, C->list); + curl_easy_setopt(C->curl, CURLOPT_POSTFIELDS, JSONPayload); + + C->CurlData = { (char *)OutputData, 0 }; + + curl_easy_setopt(C->curl, CURLOPT_WRITEFUNCTION, dumbcurlcallback); + curl_easy_setopt(C->curl, CURLOPT_WRITEDATA, (void *)&C->CurlData); + + C->curlm = curl_multi_init(); + Assert(C->curlm); + curl_multi_add_handle(C->curlm, C->curl); + + Curl_Check(C); +} + +static void +Curl_Prog_Init(curl_state *C, void *OutputData) +{ + C->curl = curl_easy_init(); + Assert(C->curl); + + C->CurlData = { (char *)OutputData, 0 }; + + curl_easy_setopt(C->curl, CURLOPT_URL, "http://127.0.0.1:7860/sdapi/v1/progress"); + curl_easy_setopt(C->curl, CURLOPT_WRITEFUNCTION, dumbcurlcallback); + curl_easy_setopt(C->curl, CURLOPT_WRITEDATA, (void *)&C->CurlData); + + C->curlm = curl_multi_init(); + Assert(C->curlm); + curl_multi_add_handle(C->curlm, C->curl); +} + + /* + int num; + CURLMcode mc = curl_multi_perform(C->curlm, &num); + Assert(!mc); + + int queue = 0; + CURLMsg *msg = curl_multi_info_read(C->curlm, &queue); + if (msg) { + CURL *e = msg->easy_handle; + if (msg->msg == CURLMSG_DONE) { + if (msg->data.result == CURLE_COULDNT_CONNECT) { + printf("Active stable-diffusion-webui instance not found at URL.\n"); + } else { + printf("curl error: %s!\n", curl_easy_strerror(msg->data.result)); + } + Assert(0); + } + } + */ + + +#if 0 + res = curl_easy_perform(curl); + /* Check for errors */ + if(res != CURLE_OK) + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + + /* Perform the request, res will get the return code */ + + /* always cleanup */ + curl_slist_free_all(list); + curl_easy_cleanup(curl); + + + curl_global_cleanup(); +#endif diff --git a/stable_diffusion.h b/stable_diffusion.h index 6e7dd54..97ae076 100644 --- a/stable_diffusion.h +++ b/stable_diffusion.h @@ -9,17 +9,24 @@ #define SD_LEN_PROMPT 256 #define SD_LEN_ADDRESS 128 +// struct sd_mode +// { +// sd_mode_txt2txt, +// sd_mode_txt2img +// } + struct sd_state { + bool32 Mode = 1; char Prompt[256]; char NegPrompt[256]; char ServerAddress[128]; - int32 Steps = 25; - int32 Width = 512; - int32 Height = 512; + int32 Steps = 10; + int32 Width = 384; + int32 Height = 384; int32 SamplerIndex = 0; real32 CFG = 7; - real32 DenoisingStrength = 0.7; + real32 DenoisingStrength = 0.2; int32 Seed = -1; }; diff --git a/undo.cpp b/undo.cpp index a86e214..e568675 100644 --- a/undo.cpp +++ b/undo.cpp @@ -1,49 +1,3 @@ -void Arbitrary_WriteInto(uint8 *Address_Read, uint8 *Address_Write, uint64 Size) -{ - uint64 i = 0; - while (i < Size) { - *(Address_Write + i) = *(Address_Read + i); - i++; - } -} - -void Arbitrary_Zero(uint8 *Address_Write, uint64 Size) -{ - uint64 i = 0; - while (i < Size) { - *(Address_Write + i) = 0; - i++; - } -} - -void Arbitrary_SwapData(memory *Memory, uint8 *Address_0, uint8 *Address_1, uint64 Size) -{ - uint8 *Buffer_Scratch = (uint8 *)Memory_PushScratch(Memory, Size); - Arbitrary_WriteInto(Address_0, Buffer_Scratch, Size); - Arbitrary_WriteInto(Address_1, Address_0, Size); - Arbitrary_WriteInto(Buffer_Scratch, Address_1, Size); - Memory_PopScratch(Memory, Size); -} - - -static void -Arbitrary_ShiftData(uint8 *Address_Start, uint8 *Address_End, uint64 ShiftAmount, int32 Direction) -{ - if (Direction > 0) { - uint8 *AddressPlayhead = Address_End; - while ((ptrsize)AddressPlayhead >= (ptrsize)Address_Start) { - *(AddressPlayhead + ShiftAmount) = *AddressPlayhead; - AddressPlayhead--; - } - } else { - uint8 *AddressPlayhead = Address_Start; - while ((ptrsize)AddressPlayhead < (ptrsize)Address_End) { - *(AddressPlayhead - ShiftAmount) = *AddressPlayhead; - AddressPlayhead++; - } - } -} - struct history_info { uint16 ActionCount_Total; uint16 ActionCount_EndOfPlayhead; @@ -249,7 +203,7 @@ static void History_Action_Add(memory *Memory, history_action ActionData, void * { void *Address_HistoryTree = Memory_AddressAtOffset(Memory, P_UndoBuffer, Info.ActionOffset_Total); void *Address_Data = Memory_AddressAtOffset(Memory, Action->TableName, Action->ByteOffset); - Arbitrary_WriteInto((uint8 *)Address_Data, (uint8 *)Address_HistoryTree, Action->Size); + Memory_Copy((uint8 *)Address_HistoryTree, (uint8 *)Address_Data, Action->Size); } else if (Action->Type == action_type_shift) { void *Address_Start = Memory_AddressAtOffset(Memory, Action->TableName, Action->ByteOffset); -- cgit v1.2.3